react-logger-app 1.1.3 → 1.1.5
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/README.md +192 -69
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,46 +1,58 @@
|
|
|
1
1
|
# ReactLoggerApp 🐞
|
|
2
2
|
|
|
3
|
-
A professional, high-performance visual logging system for Ionic React applications. Monitor logs, errors, and JSON objects in real-time with a beautiful floating UI
|
|
3
|
+
A professional, high-performance visual logging system for **Ionic React** applications. Monitor logs, errors, and JSON objects in real-time with a beautiful floating UI that works seamlessly on **iOS**, **Android**, and **Web**.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
- 🐞 **Floating UI**: Draggable, minimizable, and responsive button.
|
|
9
|
-
- 📦 **JSON Tree Viewer**: Expandable visualization for complex objects.
|
|
10
|
-
- 💾 **Persistence**: Option to store logs in `localStorage` or `IndexedDB`.
|
|
11
|
-
- 🔍 **Search & Filters**: Quickly find specific logs or filter by level.
|
|
12
|
-
- 📥 **Export**: Download logs as JSON files.
|
|
13
|
-
- 🌓 **Dark Mode**: Automatic support for system theme.
|
|
14
|
-
- 🚀 **Virtualized List**: Handles thousands of logs without performance loss.
|
|
9
|
+
## ✨ Features
|
|
15
10
|
|
|
16
|
-
|
|
11
|
+
- 🐞 **Three Log Levels**: Debug, Error, and Object
|
|
12
|
+
- � **Mobile-First Design**: Optimized for iOS and Android (WebView compatible)
|
|
13
|
+
- 🎨 **Liquid Glass UI**: Premium glassmorphism design with neon accents
|
|
14
|
+
- 🖱️ **Draggable Floating Button**: Minimizable, repositionable trigger
|
|
15
|
+
- 📦 **JSON Tree Viewer**: Expandable visualization for complex objects
|
|
16
|
+
- 💾 **Persistent Storage**: Save logs across sessions (localStorage/IndexedDB)
|
|
17
|
+
- 🔍 **Search & Filters**: Quickly find specific logs or filter by level
|
|
18
|
+
- 📥 **Export Logs**: Download as JSON files
|
|
19
|
+
- 🚀 **Virtualized List**: Handles thousands of logs without performance loss
|
|
20
|
+
- 🌐 **Cross-Platform**: Works in React components and TypeScript classes
|
|
21
|
+
- 🎯 **Zero Dependencies**: Lightweight with minimal peer dependencies
|
|
22
|
+
|
|
23
|
+
## 📦 Installation
|
|
17
24
|
|
|
18
25
|
```bash
|
|
19
26
|
npm install react-logger-app
|
|
20
27
|
# or
|
|
21
28
|
yarn add react-logger-app
|
|
29
|
+
# or
|
|
30
|
+
pnpm add react-logger-app
|
|
22
31
|
```
|
|
23
32
|
|
|
24
|
-
##
|
|
33
|
+
## 🚀 Quick Start
|
|
25
34
|
|
|
26
|
-
|
|
35
|
+
### 1. Setup Provider
|
|
36
|
+
|
|
37
|
+
Wrap your application with `LoggerProvider` and add `LoggerViewer` (typically in `App.tsx`):
|
|
27
38
|
|
|
28
39
|
```tsx
|
|
29
40
|
import { LoggerProvider, LoggerViewer } from 'react-logger-app';
|
|
41
|
+
import { IonApp } from '@ionic/react';
|
|
30
42
|
|
|
31
43
|
const App: React.FC = () => (
|
|
32
44
|
<LoggerProvider config={{ persistence: true, maxLogs: 1000 }}>
|
|
33
45
|
<IonApp>
|
|
34
|
-
{/* Your app components */}
|
|
46
|
+
{/* Your app routes and components */}
|
|
35
47
|
<LoggerViewer />
|
|
36
48
|
</IonApp>
|
|
37
49
|
</LoggerProvider>
|
|
38
50
|
);
|
|
39
|
-
```
|
|
40
51
|
|
|
41
|
-
|
|
52
|
+
export default App;
|
|
53
|
+
```
|
|
42
54
|
|
|
43
|
-
|
|
55
|
+
### 2. Use in React Components
|
|
44
56
|
|
|
45
57
|
```tsx
|
|
46
58
|
import { useLogger } from 'react-logger-app';
|
|
@@ -48,12 +60,12 @@ import { useLogger } from 'react-logger-app';
|
|
|
48
60
|
const MyComponent: React.FC = () => {
|
|
49
61
|
const { debug, error, object } = useLogger();
|
|
50
62
|
|
|
51
|
-
const handleAction = () => {
|
|
63
|
+
const handleAction = async () => {
|
|
52
64
|
debug('Process started');
|
|
53
65
|
|
|
54
66
|
try {
|
|
55
|
-
const
|
|
56
|
-
object(
|
|
67
|
+
const response = await fetchData();
|
|
68
|
+
object(response, 'API Response');
|
|
57
69
|
} catch (e) {
|
|
58
70
|
error(e as Error);
|
|
59
71
|
}
|
|
@@ -63,67 +75,178 @@ const MyComponent: React.FC = () => {
|
|
|
63
75
|
};
|
|
64
76
|
```
|
|
65
77
|
|
|
66
|
-
###
|
|
78
|
+
### 3. Use in TypeScript Classes
|
|
67
79
|
|
|
68
|
-
|
|
80
|
+
Perfect for services, utilities, and business logic outside React:
|
|
69
81
|
|
|
70
82
|
```tsx
|
|
71
83
|
import { Logger } from 'react-logger-app';
|
|
72
84
|
|
|
73
|
-
class
|
|
74
|
-
|
|
75
|
-
Logger.debug('
|
|
85
|
+
class AuthService {
|
|
86
|
+
async login(credentials: Credentials) {
|
|
87
|
+
Logger.debug('Login attempt started', 'AuthService');
|
|
76
88
|
|
|
77
89
|
try {
|
|
78
|
-
|
|
79
|
-
Logger.object(
|
|
80
|
-
|
|
81
|
-
|
|
90
|
+
const user = await api.authenticate(credentials);
|
|
91
|
+
Logger.object(user, 'Authenticated User');
|
|
92
|
+
return user;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
Logger.error(error as Error);
|
|
95
|
+
throw error;
|
|
82
96
|
}
|
|
83
97
|
}
|
|
84
98
|
}
|
|
85
99
|
```
|
|
86
100
|
|
|
87
|
-
>
|
|
88
|
-
> Logs sent via `Logger` will be buffered if the `LoggerProvider` is not yet mounted and will be flushed as soon as the UI is ready.
|
|
101
|
+
> **Note**: Logs sent via `Logger` before the provider mounts are buffered and displayed once the UI is ready.
|
|
89
102
|
|
|
90
|
-
|
|
103
|
+
## ⚙️ Configuration Options
|
|
91
104
|
|
|
92
105
|
| Option | Type | Default | Description |
|
|
93
|
-
|
|
94
|
-
| `persistence` | `boolean` | `false` | Enable log storage between sessions
|
|
95
|
-
| `persistenceDriver` | `'localStorage' \| 'indexedDB'` | `'localStorage'` |
|
|
96
|
-
| `maxLogs` | `number` | `500` | Maximum number of logs to
|
|
97
|
-
| `onLogAdded` | `(log: LogEntry) => void` | `undefined` | Callback fired
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
106
|
+
|--------|------|---------|-------------|
|
|
107
|
+
| `persistence` | `boolean` | `false` | Enable log storage between sessions |
|
|
108
|
+
| `persistenceDriver` | `'localStorage'` \| `'indexedDB'` | `'localStorage'` | Storage backend for persisted logs |
|
|
109
|
+
| `maxLogs` | `number` | `500` | Maximum number of logs to retain |
|
|
110
|
+
| `onLogAdded` | `(log: LogEntry) => void` | `undefined` | Callback fired when a log is added |
|
|
111
|
+
|
|
112
|
+
### Example with Custom Config
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
<LoggerProvider
|
|
116
|
+
config={{
|
|
117
|
+
persistence: true,
|
|
118
|
+
persistenceDriver: 'indexedDB',
|
|
119
|
+
maxLogs: 2000,
|
|
120
|
+
onLogAdded: (log) => {
|
|
121
|
+
if (log.level === 'ERROR') {
|
|
122
|
+
// Send to analytics or crash reporting
|
|
123
|
+
analytics.trackError(log);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}}
|
|
127
|
+
>
|
|
128
|
+
<App />
|
|
129
|
+
</LoggerProvider>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 📱 Platform Support
|
|
133
|
+
|
|
134
|
+
### ✅ Fully Tested On:
|
|
135
|
+
- **iOS** (Safari, WKWebView)
|
|
136
|
+
- **Android** (Chrome WebView, System WebView)
|
|
137
|
+
- **Web** (Chrome, Safari, Firefox, Edge)
|
|
138
|
+
|
|
139
|
+
### 🔧 Android-Specific Optimizations (v1.1.3+)
|
|
140
|
+
- Solid background fallback for WebView compatibility
|
|
141
|
+
- Disabled `backdrop-filter` on mobile to prevent rendering artifacts
|
|
142
|
+
- Conditional rendering to avoid z-index conflicts
|
|
143
|
+
- No animations on small screens for smoother performance
|
|
144
|
+
|
|
145
|
+
## 🎨 UI Features
|
|
146
|
+
|
|
147
|
+
### Floating Button
|
|
148
|
+
- **Draggable**: Reposition anywhere on screen
|
|
149
|
+
- **Badge Counter**: Shows unread log count
|
|
150
|
+
- **Auto-hide**: Disappears when panel is open (prevents visual conflicts)
|
|
151
|
+
- **Persistent Position**: Remembers location after drag
|
|
152
|
+
|
|
153
|
+
### Log Panel
|
|
154
|
+
- **Full-screen on Mobile**: Optimized for small screens
|
|
155
|
+
- **Virtualized Scrolling**: Smooth performance with 1000+ logs
|
|
156
|
+
- **Search Bar**: Filter logs by message or title
|
|
157
|
+
- **Level Filters**: Show only DEBUG, ERROR, or OBJECT logs
|
|
158
|
+
- **Export Button**: Download logs as JSON
|
|
159
|
+
- **Clear Button**: Remove all logs with confirmation
|
|
160
|
+
|
|
161
|
+
## 📖 API Reference
|
|
162
|
+
|
|
163
|
+
### `useLogger()` Hook
|
|
164
|
+
|
|
165
|
+
Returns an object with the following methods:
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
const {
|
|
169
|
+
debug, // (message: string) => void
|
|
170
|
+
error, // (message: string | Error) => void
|
|
171
|
+
object, // (obj: any, title?: string) => void
|
|
172
|
+
clear, // () => void
|
|
173
|
+
exportLogs, // () => LogEntry[]
|
|
174
|
+
logs, // LogEntry[]
|
|
175
|
+
unreadCount // number
|
|
176
|
+
} = useLogger();
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### `Logger` Static Class
|
|
180
|
+
|
|
181
|
+
For use outside React components:
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
Logger.debug(message: string, title?: string): void
|
|
185
|
+
Logger.error(error: Error | string, title?: string): void
|
|
186
|
+
Logger.object(data: any, title?: string): void
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### `LogEntry` Type
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
interface LogEntry {
|
|
193
|
+
id: string;
|
|
194
|
+
timestamp: string;
|
|
195
|
+
level: 'DEBUG' | 'ERROR' | 'OBJECT';
|
|
196
|
+
message: string;
|
|
197
|
+
title?: string;
|
|
198
|
+
data?: any;
|
|
199
|
+
stack?: string;
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## 🛠️ Local Development
|
|
204
|
+
|
|
205
|
+
To run the demo app and test the logger:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
# 1. Build the library
|
|
209
|
+
npm run build
|
|
210
|
+
|
|
211
|
+
# 2. Run the example app
|
|
212
|
+
cd example
|
|
213
|
+
npm install
|
|
214
|
+
npm run dev
|
|
215
|
+
|
|
216
|
+
# 3. Open http://localhost:5173
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## 🐛 Troubleshooting
|
|
220
|
+
|
|
221
|
+
### Button not visible on Android
|
|
222
|
+
- **Solution**: Update to v1.1.3+ which includes Android-specific fixes
|
|
223
|
+
- Ensure `LoggerViewer` is placed inside `IonApp` or at root level
|
|
224
|
+
- Check z-index conflicts with other fixed/absolute positioned elements
|
|
225
|
+
|
|
226
|
+
### Logs not persisting
|
|
227
|
+
- Verify `persistence: true` in config
|
|
228
|
+
- Check browser storage permissions
|
|
229
|
+
- For IndexedDB, ensure browser supports it
|
|
230
|
+
|
|
231
|
+
### Performance issues with many logs
|
|
232
|
+
- Reduce `maxLogs` config value
|
|
233
|
+
- Use `clear()` periodically
|
|
234
|
+
- Enable persistence and restart app to clear memory
|
|
235
|
+
|
|
236
|
+
## 📄 License
|
|
237
|
+
|
|
238
|
+
MIT © [Reinner Leiva](https://github.com/raysdl9012)
|
|
239
|
+
|
|
240
|
+
## 🤝 Contributing
|
|
241
|
+
|
|
242
|
+
Contributions are welcome! Please open an issue or submit a pull request.
|
|
243
|
+
|
|
244
|
+
## 📦 Package Info
|
|
245
|
+
|
|
246
|
+
- **Package**: `react-logger-app`
|
|
247
|
+
- **Repository**: [github.com/raysdl9012/react-logger](https://github.com/raysdl9012/react-logger)
|
|
248
|
+
- **NPM**: [npmjs.com/package/react-logger-app](https://www.npmjs.com/package/react-logger-app)
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
Made with ❤️ for the Ionic React community
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';var U=require('react'),idb=require('idb'),jsxRuntime=require('react/jsx-runtime'),reactVirtuoso=require('react-virtuoso');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var U__default=/*#__PURE__*/_interopDefault(U);function C(e,{insertAt:t}={}){if(typeof document>"u")return;let o=document.head||document.getElementsByTagName("head")[0],r=document.createElement("style");r.type="text/css",t==="top"&&o.firstChild?o.insertBefore(r,o.firstChild):o.appendChild(r),r.styleSheet?r.styleSheet.cssText=e:r.appendChild(document.createTextNode(e));}C(`:root{--liql-primary: #6b21a8;--liql-primary-glow: rgba(107, 33, 168, .5);--liql-error: #ff4d4d;--liql-error-glow: rgba(255, 77, 77, .4);--liql-object: #00ff88;--liql-object-glow: rgba(0, 255, 136, .4);--liql-glass-bg: rgba(15, 23, 42, .9);--liql-glass-border: rgba(255, 255, 255, .1);--liql-glass-edge: rgba(255, 255, 255, .05);--liql-text-main: #f8fafc;--liql-text-muted: #94a3b8;--liql-font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif}.liql-floatingButton{position:fixed;right:20px;bottom:20px;width:50px;height:50px;border-radius:50%;background:radial-gradient(circle at 30% 30%,rgba(255,255,255,.15),transparent),linear-gradient(135deg,#6b21a8,#4c1d95);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);box-shadow:0 8px 32px #0006,0 0 15px var(--liql-primary-glow);display:flex;align-items:center;justify-content:center;cursor:grab;z-index:99999;border:1px solid var(--liql-glass-border);transition:all .4s cubic-bezier(.175,.885,.32,1.275);font-size:26px;color:#fff;user-select:none;touch-action:none}.liql-floatingButton:hover{transform:scale(1.1) rotate(5deg);box-shadow:0 12px 40px #00000080,0 0 25px var(--liql-primary-glow)}.liql-badge{position:absolute;top:-2px;right:-2px;background:var(--liql-error);color:#fff;border-radius:12px;min-width:20px;height:20px;padding:0 6px;font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;border:2px solid #0f172a;box-shadow:0 0 10px var(--liql-error-glow)}.liql-panel{position:fixed;background:var(--liql-glass-bg);backdrop-filter:blur(25px) saturate(180%);-webkit-backdrop-filter:blur(25px) saturate(180%);box-shadow:0 20px 50px #0009,inset 0 0 0 1px var(--liql-glass-edge);border:1px solid var(--liql-glass-border);border-radius:20px;display:flex;flex-direction:column;width:440px;height:680px;right:20px;bottom:20px;z-index:999999;overflow:hidden;font-family:var(--liql-font-family);color:var(--liql-text-main);animation:liql-slideUp .4s cubic-bezier(.23,1,.32,1)}.liql-panelHeader{background:#ffffff0d;padding:16px 20px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--liql-glass-border)}.liql-title{font-weight:700;letter-spacing:.5px;text-transform:uppercase;font-size:12px;color:var(--liql-text-muted)}.liql-controls{display:flex;gap:12px}.liql-btnAction{background:#ffffff14;border:1px solid var(--liql-glass-border);color:var(--liql-text-main);width:32px;height:32px;border-radius:8px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.liql-btnAction:hover{background:#ffffff26;transform:translateY(-2px)}.liql-filterBar{padding:12px 20px;display:flex;gap:10px;background:#0003;align-items:center}.liql-searchInput{flex:1;background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px 14px;color:#fff;font-size:13px}.liql-searchInput:focus{outline:none;border-color:var(--liql-primary);background:#ffffff14}.liql-selectFilter{background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px;color:#fff;font-size:12px;cursor:pointer}.liql-logListContainer{flex:1;padding:10px}.liql-logItem{margin-bottom:10px;padding:16px;border-radius:14px;background:#ffffff08;border:1px solid var(--liql-glass-border);transition:all .3s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden}.liql-logItem:hover{background:#ffffff0f;border-color:#fff3;transform:scale(1.01)}.liql-logItem-debug{border-left:4px solid var(--liql-primary)}.liql-logItem-error{border-left:4px solid var(--liql-error);box-shadow:inset 0 0 15px var(--liql-error-glow)}.liql-logItem-object{border-left:4px solid var(--liql-object);box-shadow:inset 0 0 15px var(--liql-object-glow)}.liql-logMeta{display:flex;justify-content:space-between;margin-bottom:8px;font-size:11px;font-weight:500;text-transform:uppercase}.liql-statusTag{padding:2px 8px;border-radius:6px;font-size:9px;font-weight:700}.liql-tag-debug{background:#3498db33;color:#3498db}.liql-tag-error{background:#ff4d4d33;color:#ff4d4d}.liql-tag-object{background:#0f83;color:#0f8}.liql-logTime{color:var(--liql-text-muted)}.liql-logContent{font-size:14px;line-height:1.5;color:#e2e8f0}.liql-expandedContent{margin-top:12px;padding:12px;background:#0000004d;border-radius:10px;font-family:JetBrains Mono,monospace;font-size:12px;border:1px solid var(--liql-glass-border);color:#a5f3fc;overflow-x:auto}.liql-footerActions{padding:14px 20px;background:#0003;display:flex;justify-content:space-between;align-items:center;border-top:1px solid var(--liql-glass-border)}.liql-storageInfo{font-size:10px;color:var(--liql-text-muted)}.liql-btnClose{background:linear-gradient(135deg,var(--liql-primary),#2980b9);border:none;padding:8px 16px;border-radius:8px;color:#fff;font-weight:600;font-size:13px;cursor:pointer;box-shadow:0 4px 12px var(--liql-primary-glow)}@keyframes liql-slideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}@media(max-width:600px){.liql-panel{width:100%!important;height:100%!important;bottom:0!important;right:0!important;left:0!important;border-radius:0;animation:none;background:#0f172a!important;backdrop-filter:none!important;-webkit-backdrop-filter:none!important}}
|
|
2
|
-
`);var
|
|
1
|
+
'use strict';var U=require('react'),idb=require('idb'),jsxRuntime=require('react/jsx-runtime'),reactVirtuoso=require('react-virtuoso');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var U__default=/*#__PURE__*/_interopDefault(U);Object.hasOwn||(Object.hasOwn=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)});function C(e,{insertAt:t}={}){if(typeof document>"u")return;let o=document.head||document.getElementsByTagName("head")[0],r=document.createElement("style");r.type="text/css",t==="top"&&o.firstChild?o.insertBefore(r,o.firstChild):o.appendChild(r),r.styleSheet?r.styleSheet.cssText=e:r.appendChild(document.createTextNode(e));}C(`:root{--liql-primary: #6b21a8;--liql-primary-glow: rgba(107, 33, 168, .5);--liql-error: #ff4d4d;--liql-error-glow: rgba(255, 77, 77, .4);--liql-object: #00ff88;--liql-object-glow: rgba(0, 255, 136, .4);--liql-glass-bg: rgba(15, 23, 42, .9);--liql-glass-border: rgba(255, 255, 255, .1);--liql-glass-edge: rgba(255, 255, 255, .05);--liql-text-main: #f8fafc;--liql-text-muted: #94a3b8;--liql-font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif}.liql-floatingButton{position:fixed;right:20px;bottom:20px;width:50px;height:50px;border-radius:50%;background:radial-gradient(circle at 30% 30%,rgba(255,255,255,.15),transparent),linear-gradient(135deg,#6b21a8,#4c1d95);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);box-shadow:0 8px 32px #0006,0 0 15px var(--liql-primary-glow);display:flex;align-items:center;justify-content:center;cursor:grab;z-index:99999;border:1px solid var(--liql-glass-border);transition:all .4s cubic-bezier(.175,.885,.32,1.275);font-size:26px;color:#fff;user-select:none;touch-action:none}.liql-floatingButton:hover{transform:scale(1.1) rotate(5deg);box-shadow:0 12px 40px #00000080,0 0 25px var(--liql-primary-glow)}.liql-badge{position:absolute;top:-2px;right:-2px;background:var(--liql-error);color:#fff;border-radius:12px;min-width:20px;height:20px;padding:0 6px;font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;border:2px solid #0f172a;box-shadow:0 0 10px var(--liql-error-glow)}.liql-panel{position:fixed;background:var(--liql-glass-bg);backdrop-filter:blur(25px) saturate(180%);-webkit-backdrop-filter:blur(25px) saturate(180%);box-shadow:0 20px 50px #0009,inset 0 0 0 1px var(--liql-glass-edge);border:1px solid var(--liql-glass-border);border-radius:20px;display:flex;flex-direction:column;width:440px;height:680px;right:20px;bottom:20px;z-index:999999;overflow:hidden;font-family:var(--liql-font-family);color:var(--liql-text-main);animation:liql-slideUp .4s cubic-bezier(.23,1,.32,1)}.liql-panelHeader{background:#ffffff0d;padding:16px 20px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--liql-glass-border)}.liql-title{font-weight:700;letter-spacing:.5px;text-transform:uppercase;font-size:12px;color:var(--liql-text-muted)}.liql-controls{display:flex;gap:12px}.liql-btnAction{background:#ffffff14;border:1px solid var(--liql-glass-border);color:var(--liql-text-main);width:32px;height:32px;border-radius:8px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.liql-btnAction:hover{background:#ffffff26;transform:translateY(-2px)}.liql-filterBar{padding:12px 20px;display:flex;gap:10px;background:#0003;align-items:center}.liql-searchInput{flex:1;background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px 14px;color:#fff;font-size:13px}.liql-searchInput:focus{outline:none;border-color:var(--liql-primary);background:#ffffff14}.liql-selectFilter{background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px;color:#fff;font-size:12px;cursor:pointer}.liql-logListContainer{flex:1;padding:10px}.liql-logItem{margin-bottom:10px;padding:16px;border-radius:14px;background:#ffffff08;border:1px solid var(--liql-glass-border);transition:all .3s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden}.liql-logItem:hover{background:#ffffff0f;border-color:#fff3;transform:scale(1.01)}.liql-logItem-debug{border-left:4px solid var(--liql-primary)}.liql-logItem-error{border-left:4px solid var(--liql-error);box-shadow:inset 0 0 15px var(--liql-error-glow)}.liql-logItem-object{border-left:4px solid var(--liql-object);box-shadow:inset 0 0 15px var(--liql-object-glow)}.liql-logMeta{display:flex;justify-content:space-between;margin-bottom:8px;font-size:11px;font-weight:500;text-transform:uppercase}.liql-statusTag{padding:2px 8px;border-radius:6px;font-size:9px;font-weight:700}.liql-tag-debug{background:#3498db33;color:#3498db}.liql-tag-error{background:#ff4d4d33;color:#ff4d4d}.liql-tag-object{background:#0f83;color:#0f8}.liql-logTime{color:var(--liql-text-muted)}.liql-logContent{font-size:14px;line-height:1.5;color:#e2e8f0}.liql-expandedContent{margin-top:12px;padding:12px;background:#0000004d;border-radius:10px;font-family:JetBrains Mono,monospace;font-size:12px;border:1px solid var(--liql-glass-border);color:#a5f3fc;overflow-x:auto}.liql-footerActions{padding:14px 20px;background:#0003;display:flex;justify-content:space-between;align-items:center;border-top:1px solid var(--liql-glass-border)}.liql-storageInfo{font-size:10px;color:var(--liql-text-muted)}.liql-btnClose{background:linear-gradient(135deg,var(--liql-primary),#2980b9);border:none;padding:8px 16px;border-radius:8px;color:#fff;font-weight:600;font-size:13px;cursor:pointer;box-shadow:0 4px 12px var(--liql-primary-glow)}@keyframes liql-slideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}@media(max-width:600px){.liql-panel{width:100%!important;height:100%!important;bottom:0!important;right:0!important;left:0!important;border-radius:0;animation:none;background:#0f172a!important;backdrop-filter:none!important;-webkit-backdrop-filter:none!important}}
|
|
2
|
+
`);var q=class{key;constructor(t="ionic_react_logger_logs"){this.key=t;}async save(t){try{localStorage.setItem(this.key,JSON.stringify(t));}catch(o){console.error("Failed to save logs to localStorage",o);}}async load(){try{let t=localStorage.getItem(this.key);return t?JSON.parse(t):[]}catch(t){return console.error("Failed to load logs from localStorage",t),[]}}async clear(){localStorage.removeItem(this.key);}};var G="IonicReactLoggerDB",v="logs",F=1,E=class{dbPromise;constructor(){this.dbPromise=idb.openDB(G,F,{upgrade(t){t.objectStoreNames.contains(v)||t.createObjectStore(v,{keyPath:"id"});}});}async save(t){let r=(await this.dbPromise).transaction(v,"readwrite"),i=r.objectStore(v);await i.clear();for(let s of t)await i.put(s);await r.done;}async load(){return (await this.dbPromise).getAll(v)}async clear(){let o=(await this.dbPromise).transaction(v,"readwrite");await o.objectStore(v).clear(),await o.done;}};function k(e){return e==="indexedDB"?new E:new q}var p=class{static dispatch=null;static logBuffer=[];static onLogAddedCallback;static _setDispatcher(t,o){this.dispatch=t,this.onLogAddedCallback=o,this.logBuffer.length>0&&(this.logBuffer.forEach(r=>{this.dispatch({type:"ADD_LOG",log:r}),this.onLogAddedCallback?.(r);}),this.logBuffer=[]);}static createLog(t,o,r){return {id:Math.random().toString(36).substring(2,9),level:t,message:o,timestamp:new Date().toISOString(),...r}}static addLog(t){this.dispatch?(this.dispatch({type:"ADD_LOG",log:t}),this.onLogAddedCallback?.(t)):this.logBuffer.push(t);}static debug(t,o){this.addLog(this.createLog("DEBUG",t,{title:o}));}static error(t,o){let r=t instanceof Error?t.message:t,i=t instanceof Error?t.stack:void 0;this.addLog(this.createLog("ERROR",r,{title:o||"Error",stack:i}));}static object(t,o){this.addLog(this.createLog("OBJECT","Object visualization",{title:o||"Data Object",data:t}));}static clear(){this.dispatch?this.dispatch({type:"CLEAR_LOGS"}):this.logBuffer=[];}};var D={logs:[],config:{persistence:false,persistenceDriver:"localStorage",maxLogs:500},unreadCount:0};function X(e,t){switch(t.type){case "ADD_LOG":{let o=[t.log,...e.logs].slice(0,e.config.maxLogs);return {...e,logs:o}}case "SET_LOGS":return {...e,logs:[...e.logs,...t.logs].slice(0,e.config.maxLogs)};case "CLEAR_LOGS":return {...e,logs:[],unreadCount:0};case "SET_CONFIG":return {...e,config:{...e.config,...t.config}};case "RESET_UNREAD":return {...e,unreadCount:0};case "INCREMENT_UNREAD":return {...e,unreadCount:e.unreadCount+1};default:return e}}var O=U.createContext(void 0),ve=({children:e,config:t})=>{let[o,r]=U.useReducer(X,{...D,config:{...D.config,...t}}),[i,s]=U__default.default.useState(false),a=U.useRef(null);return U.useEffect(()=>{p._setDispatcher(r,o.config.onLogAdded),o.config.persistence&&(a.current=k(o.config.persistenceDriver||"localStorage"),a.current.load().then(n=>{r({type:"SET_LOGS",logs:n});}));},[o.config.persistence,o.config.persistenceDriver]),U.useEffect(()=>{o.config.persistence&&a.current&&a.current.save(o.logs);},[o.logs,o.config.persistence]),jsxRuntime.jsx(O.Provider,{value:{state:o,dispatch:r,isPanelOpen:i,setIsPanelOpen:s},children:e})},u=()=>{let e=U.useContext(O);if(!e)throw new Error("useLoggerContext must be used within a LoggerProvider");return e};var Ce=()=>{let{state:e}=u(),t=U.useCallback((a,n)=>{p.debug(a,n);},[]),o=U.useCallback((a,n)=>{p.error(a,n);},[]),r=U.useCallback((a,n)=>{p.object(a,n);},[]),i=U.useCallback(()=>{p.clear();},[]),s=U.useCallback(()=>{let a="data:text/json;charset=utf-8,"+encodeURIComponent(JSON.stringify(e.logs,null,2)),n=document.createElement("a");n.setAttribute("href",a),n.setAttribute("download",`logs_${new Date().getTime()}.json`),document.body.appendChild(n),n.click(),n.remove();},[e.logs]);return {debug:t,error:o,object:r,clear:i,exportLogs:s,logs:e.logs,unreadCount:e.unreadCount}};var P=()=>{let{state:e,setIsPanelOpen:t}=u(),[o,r]=U.useState(null),i=U.useRef(false),s=U.useRef({x:0,y:0}),a=l=>{let c=l.currentTarget.getBoundingClientRect();i.current=true,s.current={x:l.clientX-c.left,y:l.clientY-c.top};},n=l=>{let c=l.currentTarget.getBoundingClientRect();i.current=true;let g=l.touches[0];s.current={x:g.clientX-c.left,y:g.clientY-c.top};},m=U.useCallback((l,c)=>{if(!i.current)return;let g=Math.max(10,Math.min(window.innerWidth-60,l-s.current.x)),h=Math.max(10,Math.min(window.innerHeight-60,c-s.current.y));r({x:g,y:h});},[]);U.useEffect(()=>{let l=h=>m(h.clientX,h.clientY),c=h=>m(h.touches[0].clientX,h.touches[0].clientY),g=()=>{i.current=false;};return window.addEventListener("mousemove",l),window.addEventListener("touchmove",c,{passive:false}),window.addEventListener("mouseup",g),window.addEventListener("touchend",g),()=>{window.removeEventListener("mousemove",l),window.removeEventListener("touchmove",c),window.removeEventListener("mouseup",g),window.removeEventListener("touchend",g);}},[m]),U.useEffect(()=>{let l=()=>{o&&r(c=>c?{x:Math.min(c.x,window.innerWidth-60),y:Math.min(c.y,window.innerHeight-60)}:null);};return window.addEventListener("resize",l),()=>window.removeEventListener("resize",l)},[o]);let x=()=>{i.current||t(true);},b=o?{left:`${o.x}px`,top:`${o.y}px`,right:"auto",bottom:"auto"}:{};return jsxRuntime.jsx("div",{className:"liql-floatingButton",style:b,onMouseDown:a,onTouchStart:n,onClick:x,"aria-label":"Open Logger",children:e.unreadCount>0&&jsxRuntime.jsx("div",{className:"liql-badge",children:e.unreadCount})})};var T=({log:e})=>{let[t,o]=U.useState(false),r=n=>new Date(n).toTimeString().split(" ")[0],i=n=>{try{return jsxRuntime.jsx("pre",{className:"liql-expandedContent",children:JSON.stringify(n,null,2)})}catch{return jsxRuntime.jsx("div",{children:"Error parsing object"})}},s=n=>{switch(n){case "DEBUG":return "\u{1F41E}";case "ERROR":return "\u274C";case "OBJECT":return "\u{1F4E6}";default:return "\u{1F4DD}"}},a=e.level.toLowerCase();return jsxRuntime.jsxs("div",{className:`liql-logItem liql-logItem-${a}`,onClick:()=>o(!t),children:[jsxRuntime.jsxs("div",{className:"liql-logMeta",children:[jsxRuntime.jsxs("span",{className:`liql-statusTag liql-tag-${a}`,children:[s(e.level)," ",e.level]}),jsxRuntime.jsx("span",{className:"liql-logTime",children:r(e.timestamp)})]}),jsxRuntime.jsxs("div",{className:"liql-logContent",children:[e.title&&jsxRuntime.jsxs("strong",{style:{color:"var(--liql-primary)"},children:[e.title,": "]}),e.message]}),t&&jsxRuntime.jsxs("div",{className:"liql-expandedContent",children:[e.stack&&jsxRuntime.jsxs("div",{style:{color:"var(--liql-error)",marginBottom:"8px"},children:[jsxRuntime.jsx("strong",{children:"Stack Trace:"}),jsxRuntime.jsx("pre",{style:{whiteSpace:"pre-wrap",fontSize:"10px",marginTop:"4px"},children:e.stack})]}),e.data&&jsxRuntime.jsxs("div",{children:[jsxRuntime.jsx("strong",{children:"Payload:"}),i(e.data)]}),!e.data&&!e.stack&&jsxRuntime.jsxs("div",{children:["Full message: ",e.message]})]})]})};var B=({logs:e,filter:t,search:o})=>{let r=U__default.default.useMemo(()=>e.filter(i=>{let s=t==="ALL"||i.level===t,a=o===""||i.message.toLowerCase().includes(o.toLowerCase())||(i.title||"").toLowerCase().includes(o.toLowerCase());return s&&a}).reverse(),[e,t,o]);return jsxRuntime.jsx("div",{className:"liql-logListContainer",children:jsxRuntime.jsx(reactVirtuoso.Virtuoso,{style:{height:"100%"},data:r,itemContent:(i,s)=>jsxRuntime.jsx(T,{log:s},s.id)})})};var M=()=>{let{state:e,setIsPanelOpen:t,dispatch:o}=u(),[r,i]=U.useState("ALL"),[s,a]=U.useState(""),n=()=>{confirm("Are you sure you want to clear all logs?")&&o({type:"CLEAR_LOGS"});},m=()=>{let x="data:text/json;charset=utf-8,"+encodeURIComponent(JSON.stringify(e.logs,null,2)),b=document.createElement("a");b.setAttribute("href",x),b.setAttribute("download",`logs_${new Date().getTime()}.json`),document.body.appendChild(b),b.click(),b.remove();};return e?jsxRuntime.jsxs("div",{className:"liql-panel",children:[jsxRuntime.jsxs("div",{className:"liql-panelHeader",children:[jsxRuntime.jsx("div",{className:"liql-titleGroup",children:jsxRuntime.jsxs("span",{className:"liql-title",children:["ReactLoggerApp console [",e.logs.length,"]"]})}),jsxRuntime.jsxs("div",{className:"liql-controls",children:[jsxRuntime.jsx("button",{className:"liql-btnAction",onClick:m,title:"Export JSON",children:"\u{1F4E5}"}),jsxRuntime.jsx("button",{className:"liql-btnAction",onClick:n,title:"Clear Logs",children:"\u{1F5D1}\uFE0F"}),jsxRuntime.jsx("button",{className:"liql-btnAction",onClick:()=>t(false),title:"Minimize",children:"\u2796"})]})]}),jsxRuntime.jsxs("div",{className:"liql-filterBar",children:[jsxRuntime.jsx("input",{type:"text",placeholder:"Search entries...",className:"liql-searchInput",value:s,onChange:x=>a(x.target.value)}),jsxRuntime.jsxs("select",{className:"liql-selectFilter",value:r,onChange:x=>i(x.target.value),children:[jsxRuntime.jsx("option",{value:"ALL",children:"ALL"}),jsxRuntime.jsx("option",{value:"DEBUG",children:"DEBUG"}),jsxRuntime.jsx("option",{value:"ERROR",children:"ERROR"}),jsxRuntime.jsx("option",{value:"OBJECT",children:"OBJECTS"})]})]}),jsxRuntime.jsx(B,{logs:e.logs,filter:r,search:s}),jsxRuntime.jsxs("div",{className:"liql-footerActions",children:[jsxRuntime.jsx("div",{className:"liql-storageInfo",children:e.config.persistence?`DRIVER: ${e.config.persistenceDriver?.toUpperCase()}`:"SESSION MODE"}),jsxRuntime.jsx("button",{className:"liql-btnClose",onClick:()=>t(false),children:"CLOSE CONSOLE"})]})]}):null};var We=()=>{let{isPanelOpen:e}=u();return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[!e&&jsxRuntime.jsx(P,{}),e&&jsxRuntime.jsx(M,{})]})};exports.Logger=p;exports.LoggerProvider=ve;exports.LoggerViewer=We;exports.useLogger=Ce;exports.useLoggerContext=u;//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["#style-inject:#style-inject","../src/styles/logger.css","../src/storage/localStorageDriver.ts","../src/storage/indexedDBDriver.ts","../src/storage/index.ts","../src/Logger.ts","../src/context/LoggerContext.tsx","../src/hooks/useLogger.ts","../src/components/FloatingButton.tsx","../src/components/LogItem.tsx","../src/components/LogList.tsx","../src/components/LogPanel.tsx","../src/components/LoggerViewer.tsx"],"names":["styleInject","css","insertAt","head","style","LocalStorageDriver","key","logs","e","data","DB_NAME","STORE_NAME","DB_VERSION","IndexedDBDriver","openDB","db","tx","store","log","getStorageDriver","type","Logger","dispatch","onLogAdded","level","message","extra","title","err","stack","initialState","loggerReducer","state","action","newLogs","LoggerContext","createContext","LoggerProvider","children","config","useReducer","isPanelOpen","setIsPanelOpen","React","storageRef","useRef","useEffect","loadedLogs","jsx","useLoggerContext","context","useContext","useLogger","debug","useCallback","error","object","clear","exportLogs","dataStr","downloadAnchorNode","FloatingButton","position","setPosition","useState","isDragging","dragOffset","handleMouseDown","rect","handleTouchStart","touch","handleMove","clientX","clientY","nextX","nextY","onMouseMove","onTouchMove","onEnd","handleResize","prev","handleClick","dynamicStyle","LogItem","isExpanded","setIsExpanded","formatTime","isoString","renderJson","getIcon","levelClass","jsxs","LogList","filter","search","filteredLogs","matchesFilter","matchesSearch","Virtuoso","_index","LogPanel","setFilter","setSearch","clearLogs","LoggerViewer","Fragment"],"mappings":"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","file":"index.js","sourcesContent":["\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\":root{--liql-primary: #6b21a8;--liql-primary-glow: rgba(107, 33, 168, .5);--liql-error: #ff4d4d;--liql-error-glow: rgba(255, 77, 77, .4);--liql-object: #00ff88;--liql-object-glow: rgba(0, 255, 136, .4);--liql-glass-bg: rgba(15, 23, 42, .9);--liql-glass-border: rgba(255, 255, 255, .1);--liql-glass-edge: rgba(255, 255, 255, .05);--liql-text-main: #f8fafc;--liql-text-muted: #94a3b8;--liql-font-family: \\\"Inter\\\", -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, sans-serif}.liql-floatingButton{position:fixed;right:20px;bottom:20px;width:50px;height:50px;border-radius:50%;background:radial-gradient(circle at 30% 30%,rgba(255,255,255,.15),transparent),linear-gradient(135deg,#6b21a8,#4c1d95);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);box-shadow:0 8px 32px #0006,0 0 15px var(--liql-primary-glow);display:flex;align-items:center;justify-content:center;cursor:grab;z-index:99999;border:1px solid var(--liql-glass-border);transition:all .4s cubic-bezier(.175,.885,.32,1.275);font-size:26px;color:#fff;user-select:none;touch-action:none}.liql-floatingButton:hover{transform:scale(1.1) rotate(5deg);box-shadow:0 12px 40px #00000080,0 0 25px var(--liql-primary-glow)}.liql-badge{position:absolute;top:-2px;right:-2px;background:var(--liql-error);color:#fff;border-radius:12px;min-width:20px;height:20px;padding:0 6px;font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;border:2px solid #0f172a;box-shadow:0 0 10px var(--liql-error-glow)}.liql-panel{position:fixed;background:var(--liql-glass-bg);backdrop-filter:blur(25px) saturate(180%);-webkit-backdrop-filter:blur(25px) saturate(180%);box-shadow:0 20px 50px #0009,inset 0 0 0 1px var(--liql-glass-edge);border:1px solid var(--liql-glass-border);border-radius:20px;display:flex;flex-direction:column;width:440px;height:680px;right:20px;bottom:20px;z-index:999999;overflow:hidden;font-family:var(--liql-font-family);color:var(--liql-text-main);animation:liql-slideUp .4s cubic-bezier(.23,1,.32,1)}.liql-panelHeader{background:#ffffff0d;padding:16px 20px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--liql-glass-border)}.liql-title{font-weight:700;letter-spacing:.5px;text-transform:uppercase;font-size:12px;color:var(--liql-text-muted)}.liql-controls{display:flex;gap:12px}.liql-btnAction{background:#ffffff14;border:1px solid var(--liql-glass-border);color:var(--liql-text-main);width:32px;height:32px;border-radius:8px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.liql-btnAction:hover{background:#ffffff26;transform:translateY(-2px)}.liql-filterBar{padding:12px 20px;display:flex;gap:10px;background:#0003;align-items:center}.liql-searchInput{flex:1;background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px 14px;color:#fff;font-size:13px}.liql-searchInput:focus{outline:none;border-color:var(--liql-primary);background:#ffffff14}.liql-selectFilter{background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px;color:#fff;font-size:12px;cursor:pointer}.liql-logListContainer{flex:1;padding:10px}.liql-logItem{margin-bottom:10px;padding:16px;border-radius:14px;background:#ffffff08;border:1px solid var(--liql-glass-border);transition:all .3s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden}.liql-logItem:hover{background:#ffffff0f;border-color:#fff3;transform:scale(1.01)}.liql-logItem-debug{border-left:4px solid var(--liql-primary)}.liql-logItem-error{border-left:4px solid var(--liql-error);box-shadow:inset 0 0 15px var(--liql-error-glow)}.liql-logItem-object{border-left:4px solid var(--liql-object);box-shadow:inset 0 0 15px var(--liql-object-glow)}.liql-logMeta{display:flex;justify-content:space-between;margin-bottom:8px;font-size:11px;font-weight:500;text-transform:uppercase}.liql-statusTag{padding:2px 8px;border-radius:6px;font-size:9px;font-weight:700}.liql-tag-debug{background:#3498db33;color:#3498db}.liql-tag-error{background:#ff4d4d33;color:#ff4d4d}.liql-tag-object{background:#0f83;color:#0f8}.liql-logTime{color:var(--liql-text-muted)}.liql-logContent{font-size:14px;line-height:1.5;color:#e2e8f0}.liql-expandedContent{margin-top:12px;padding:12px;background:#0000004d;border-radius:10px;font-family:JetBrains Mono,monospace;font-size:12px;border:1px solid var(--liql-glass-border);color:#a5f3fc;overflow-x:auto}.liql-footerActions{padding:14px 20px;background:#0003;display:flex;justify-content:space-between;align-items:center;border-top:1px solid var(--liql-glass-border)}.liql-storageInfo{font-size:10px;color:var(--liql-text-muted)}.liql-btnClose{background:linear-gradient(135deg,var(--liql-primary),#2980b9);border:none;padding:8px 16px;border-radius:8px;color:#fff;font-weight:600;font-size:13px;cursor:pointer;box-shadow:0 4px 12px var(--liql-primary-glow)}@keyframes liql-slideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}@media(max-width:600px){.liql-panel{width:100%!important;height:100%!important;bottom:0!important;right:0!important;left:0!important;border-radius:0;animation:none;background:#0f172a!important;backdrop-filter:none!important;-webkit-backdrop-filter:none!important}}\\n\")","import { LogEntry, StorageDriver } from '../types';\n\nexport class LocalStorageDriver implements StorageDriver {\n private key: string;\n\n constructor(key: string = 'ionic_react_logger_logs') {\n this.key = key;\n }\n\n async save(logs: LogEntry[]): Promise<void> {\n try {\n localStorage.setItem(this.key, JSON.stringify(logs));\n } catch (e) {\n console.error('Failed to save logs to localStorage', e);\n }\n }\n\n async load(): Promise<LogEntry[]> {\n try {\n const data = localStorage.getItem(this.key);\n return data ? JSON.parse(data) : [];\n } catch (e) {\n console.error('Failed to load logs from localStorage', e);\n return [];\n }\n }\n\n async clear(): Promise<void> {\n localStorage.removeItem(this.key);\n }\n}\n","import { openDB, IDBPDatabase } from 'idb';\nimport { LogEntry, StorageDriver } from '../types';\n\nconst DB_NAME = 'IonicReactLoggerDB';\nconst STORE_NAME = 'logs';\nconst DB_VERSION = 1;\n\nexport class IndexedDBDriver implements StorageDriver {\n private dbPromise: Promise<IDBPDatabase>;\n\n constructor() {\n this.dbPromise = openDB(DB_NAME, DB_VERSION, {\n upgrade(db) {\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME, { keyPath: 'id' });\n }\n },\n });\n }\n\n async save(logs: LogEntry[]): Promise<void> {\n const db = await this.dbPromise;\n const tx = db.transaction(STORE_NAME, 'readwrite');\n const store = tx.objectStore(STORE_NAME);\n\n // Clear existing logs first or manage them as needed\n // Simple implementation: clear and re-save everything to match the expected behavior of StorageDriver\n await store.clear();\n for (const log of logs) {\n await store.put(log);\n }\n await tx.done;\n }\n\n async load(): Promise<LogEntry[]> {\n const db = await this.dbPromise;\n return db.getAll(STORE_NAME);\n }\n\n async clear(): Promise<void> {\n const db = await this.dbPromise;\n const tx = db.transaction(STORE_NAME, 'readwrite');\n await tx.objectStore(STORE_NAME).clear();\n await tx.done;\n }\n}\n","import { StorageDriver, LogEntry } from '../types';\nimport { LocalStorageDriver } from './localStorageDriver';\nimport { IndexedDBDriver } from './indexedDBDriver';\n\nexport function getStorageDriver(type: 'localStorage' | 'indexedDB'): StorageDriver {\n if (type === 'indexedDB') {\n return new IndexedDBDriver();\n }\n return new LocalStorageDriver();\n}\n\nexport * from './localStorageDriver';\nexport * from './indexedDBDriver';\n","import { LogEntry, LogLevel } from './types';\n\ntype LoggerDispatch = (action: { type: 'ADD_LOG'; log: LogEntry } | { type: 'CLEAR_LOGS' }) => void;\n\n/**\n * Global Logger class to support logging from plain TypeScript classes\n * and handle early logs before the React Provider is mounted.\n */\nexport class Logger {\n private static dispatch: LoggerDispatch | null = null;\n private static logBuffer: LogEntry[] = [];\n private static onLogAddedCallback?: (log: LogEntry) => void;\n\n /**\n * Internal method to initialize the dispatcher from the React context.\n */\n static _setDispatcher(dispatch: LoggerDispatch, onLogAdded?: (log: LogEntry) => void) {\n this.dispatch = dispatch;\n this.onLogAddedCallback = onLogAdded;\n\n // Flush buffer\n if (this.logBuffer.length > 0) {\n this.logBuffer.forEach(log => {\n this.dispatch!({ type: 'ADD_LOG', log });\n this.onLogAddedCallback?.(log);\n });\n this.logBuffer = [];\n }\n }\n\n private static createLog(level: LogLevel, message: string, extra?: { title?: string, data?: any, stack?: string }): LogEntry {\n return {\n id: Math.random().toString(36).substring(2, 9),\n level,\n message,\n timestamp: new Date().toISOString(),\n ...extra\n };\n }\n\n private static addLog(log: LogEntry) {\n if (this.dispatch) {\n this.dispatch({ type: 'ADD_LOG', log });\n this.onLogAddedCallback?.(log);\n } else {\n this.logBuffer.push(log);\n }\n }\n\n /**\n * Log a debug message (Blue neon)\n */\n static debug(message: string, title?: string) {\n this.addLog(this.createLog('DEBUG', message, { title }));\n }\n\n /**\n * Log an error (Red neon). Supports Error objects for automatic stack trace capture.\n */\n static error(err: string | Error, title?: string) {\n const message = err instanceof Error ? err.message : err;\n const stack = err instanceof Error ? err.stack : undefined;\n this.addLog(this.createLog('ERROR', message, { title: title || 'Error', stack }));\n }\n\n /**\n * Log an object for visualization (Green neon).\n */\n static object(data: any, title?: string) {\n this.addLog(this.createLog('OBJECT', 'Object visualization', { title: title || 'Data Object', data }));\n }\n\n /**\n * Clear all logs.\n */\n static clear() {\n if (this.dispatch) {\n this.dispatch({ type: 'CLEAR_LOGS' });\n } else {\n this.logBuffer = [];\n }\n }\n}\n","import React, { createContext, useContext, useReducer, useEffect, useCallback, useRef } from 'react';\nimport { LogEntry, LogLevel, LoggerConfig, StorageDriver } from '../types';\nimport { getStorageDriver } from '../storage';\nimport { Logger } from '../Logger';\n\ninterface LoggerState {\n logs: LogEntry[];\n config: LoggerConfig;\n unreadCount: number;\n}\n\ntype LoggerAction =\n | { type: 'ADD_LOG'; log: LogEntry }\n | { type: 'SET_LOGS'; logs: LogEntry[] }\n | { type: 'CLEAR_LOGS' }\n | { type: 'SET_CONFIG'; config: Partial<LoggerConfig> }\n | { type: 'RESET_UNREAD' }\n | { type: 'INCREMENT_UNREAD' };\n\nconst initialState: LoggerState = {\n logs: [],\n config: {\n persistence: false,\n persistenceDriver: 'localStorage',\n maxLogs: 500,\n },\n unreadCount: 0,\n};\n\nfunction loggerReducer(state: LoggerState, action: LoggerAction): LoggerState {\n switch (action.type) {\n case 'ADD_LOG': {\n const newLogs = [action.log, ...state.logs].slice(0, state.config.maxLogs);\n return {\n ...state,\n logs: newLogs,\n };\n }\n case 'SET_LOGS':\n return { ...state, logs: [...state.logs, ...action.logs].slice(0, state.config.maxLogs) };\n case 'CLEAR_LOGS':\n return { ...state, logs: [], unreadCount: 0 };\n case 'SET_CONFIG':\n return { ...state, config: { ...state.config, ...action.config } };\n case 'RESET_UNREAD':\n return { ...state, unreadCount: 0 };\n case 'INCREMENT_UNREAD':\n return { ...state, unreadCount: state.unreadCount + 1 };\n default:\n return state;\n }\n}\n\ninterface LoggerContextType {\n state: LoggerState;\n dispatch: React.Dispatch<LoggerAction>;\n isPanelOpen: boolean;\n setIsPanelOpen: (open: boolean) => void;\n}\n\nconst LoggerContext = createContext<LoggerContextType | undefined>(undefined);\n\n/**\n * Provides the logging context to all child components.\n * This should wrap your entire application (e.g. in App.tsx).\n * \n * @param config Optional initial configuration for persistence and limits.\n */\nexport const LoggerProvider: React.FC<{ children: React.ReactNode; config?: LoggerConfig }> = ({\n children,\n config,\n}) => {\n const [state, dispatch] = useReducer(loggerReducer, {\n ...initialState,\n config: { ...initialState.config, ...config },\n });\n const [isPanelOpen, setIsPanelOpen] = React.useState(false);\n const storageRef = useRef<StorageDriver | null>(null);\n\n // Initialize storage driver and Logger singleton\n useEffect(() => {\n Logger._setDispatcher(dispatch, state.config.onLogAdded);\n\n if (state.config.persistence) {\n storageRef.current = getStorageDriver(state.config.persistenceDriver || 'localStorage');\n storageRef.current.load().then((loadedLogs) => {\n dispatch({ type: 'SET_LOGS', logs: loadedLogs });\n });\n }\n }, [state.config.persistence, state.config.persistenceDriver]);\n\n // Persist logs when they change\n useEffect(() => {\n if (state.config.persistence && storageRef.current) {\n storageRef.current.save(state.logs);\n }\n }, [state.logs, state.config.persistence]);\n\n return (\n <LoggerContext.Provider value={{ state, dispatch, isPanelOpen, setIsPanelOpen }}>\n {children}\n </LoggerContext.Provider>\n );\n};\n\n/**\n * Internal hook to access the logger context state.\n * Use the public `useLogger` hook for standard logging operations.\n */\nexport const useLoggerContext = () => {\n const context = useContext(LoggerContext);\n if (!context) {\n throw new Error('useLoggerContext must be used within a LoggerProvider');\n }\n return context;\n};\n","import { useCallback } from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\nimport { Logger } from '../Logger';\n\n/**\n * Main hook to interact with the Liquid Glass Logger.\n * \n * Provides methods for different logging levels and allows accessing\n * the current state of logs.\n * \n * @example\n * ```tsx\n * const { debug, error, object } = useLogger();\n * \n * debug('App started');\n * error(new Error('Failed to fetch'), 'API Error');\n * object({ user: 'John' }, 'Current User');\n * ```\n */\nexport const useLogger = () => {\n const { state } = useLoggerContext();\n\n /**\n * Log a debug message (Blue neon)\n */\n const debug = useCallback((message: string, title?: string) => {\n Logger.debug(message, title);\n }, []);\n\n /**\n * Log an error. If an Error object is passed, it automatically captures the stack trace.\n * (Red neon)\n */\n const error = useCallback((err: string | Error, title?: string) => {\n Logger.error(err, title);\n }, []);\n\n /**\n * Log a data object for inspection.\n * (Green neon)\n */\n const object = useCallback((data: any, title?: string) => {\n Logger.object(data, title);\n }, []);\n\n /**\n * Clears all logs from the current session and persistent storage.\n */\n const clear = useCallback(() => {\n Logger.clear();\n }, []);\n\n /**\n * Exports all logs as a JSON file download.\n */\n const exportLogs = useCallback(() => {\n const dataStr = \"data:text/json;charset=utf-8,\" + encodeURIComponent(JSON.stringify(state.logs, null, 2));\n const downloadAnchorNode = document.createElement('a');\n downloadAnchorNode.setAttribute(\"href\", dataStr);\n downloadAnchorNode.setAttribute(\"download\", `logs_${new Date().getTime()}.json`);\n document.body.appendChild(downloadAnchorNode);\n downloadAnchorNode.click();\n downloadAnchorNode.remove();\n }, [state.logs]);\n\n return {\n /** Register a debug message */\n debug,\n /** Register an error or exception */\n error,\n /** Register an object for JSON visualization */\n object,\n /** Clear all history */\n clear,\n /** Download history as JSON */\n exportLogs,\n /** List of all captured logs */\n logs: state.logs,\n /** Count of logs not yet viewed */\n unreadCount: state.unreadCount,\n };\n};\n","import React, { useState, useRef, useEffect, useCallback } from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\n\n/**\n * Draggable floating trigger button.\n * Uses hybrid positioning (CSS initial + JS drag) for maximum compatibility.\n */\nexport const FloatingButton: React.FC = () => {\n const { state, setIsPanelOpen } = useLoggerContext();\n\n // Default to null to use CSS positioning initially\n const [position, setPosition] = useState<{ x: number; y: number } | null>(null);\n const isDragging = useRef(false);\n const dragOffset = useRef({ x: 0, y: 0 });\n\n const handleMouseDown = (e: React.MouseEvent) => {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n isDragging.current = true;\n dragOffset.current = {\n x: e.clientX - rect.left,\n y: e.clientY - rect.top\n };\n };\n\n const handleTouchStart = (e: React.TouchEvent) => {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n isDragging.current = true;\n const touch = e.touches[0];\n dragOffset.current = {\n x: touch.clientX - rect.left,\n y: touch.clientY - rect.top\n };\n };\n\n const handleMove = useCallback((clientX: number, clientY: number) => {\n if (!isDragging.current) return;\n\n // Keep button within viewport\n const nextX = Math.max(10, Math.min(window.innerWidth - 60, clientX - dragOffset.current.x));\n const nextY = Math.max(10, Math.min(window.innerHeight - 60, clientY - dragOffset.current.y));\n\n setPosition({ x: nextX, y: nextY });\n }, []);\n\n useEffect(() => {\n const onMouseMove = (e: MouseEvent) => handleMove(e.clientX, e.clientY);\n const onTouchMove = (e: TouchEvent) => handleMove(e.touches[0].clientX, e.touches[0].clientY);\n const onEnd = () => {\n isDragging.current = false;\n };\n\n window.addEventListener('mousemove', onMouseMove);\n window.addEventListener('touchmove', onTouchMove, { passive: false });\n window.addEventListener('mouseup', onEnd);\n window.addEventListener('touchend', onEnd);\n\n return () => {\n window.removeEventListener('mousemove', onMouseMove);\n window.removeEventListener('touchmove', onTouchMove);\n window.removeEventListener('mouseup', onEnd);\n window.removeEventListener('touchend', onEnd);\n };\n }, [handleMove]);\n\n // Handle window resize to keep button in bounds\n useEffect(() => {\n const handleResize = () => {\n if (position) {\n setPosition(prev => {\n if (!prev) return null;\n return {\n x: Math.min(prev.x, window.innerWidth - 60),\n y: Math.min(prev.y, window.innerHeight - 60)\n };\n });\n }\n };\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, [position]);\n\n const handleClick = () => {\n if (isDragging.current) return;\n setIsPanelOpen(true);\n };\n\n // If never moved, let CSS handle it. If moved, use absolute pixel coordinates.\n const dynamicStyle: React.CSSProperties = position\n ? { left: `${position.x}px`, top: `${position.y}px`, right: 'auto', bottom: 'auto' }\n : {};\n\n return (\n <div\n className=\"liql-floatingButton\"\n style={dynamicStyle}\n onMouseDown={handleMouseDown}\n onTouchStart={handleTouchStart}\n onClick={handleClick}\n aria-label=\"Open Logger\"\n >\n {state.unreadCount > 0 && (\n <div className=\"liql-badge\">{state.unreadCount}</div>\n )}\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport { LogEntry } from '../types';\n\ninterface LogItemProps {\n log: LogEntry;\n}\n\nexport const LogItem: React.FC<LogItemProps> = ({ log }) => {\n const [isExpanded, setIsExpanded] = useState(false);\n\n const formatTime = (isoString: string) => {\n const date = new Date(isoString);\n return date.toTimeString().split(' ')[0];\n };\n\n const renderJson = (data: any) => {\n try {\n return (\n <pre className=\"liql-expandedContent\">\n {JSON.stringify(data, null, 2)}\n </pre>\n );\n } catch (e) {\n return <div>Error parsing object</div>;\n }\n };\n\n const getIcon = (level: string) => {\n switch (level) {\n case 'DEBUG': return '🐞';\n case 'ERROR': return '❌';\n case 'OBJECT': return '📦';\n default: return '📝';\n }\n };\n\n const levelClass = log.level.toLowerCase();\n\n return (\n <div\n className={`liql-logItem liql-logItem-${levelClass}`}\n onClick={() => setIsExpanded(!isExpanded)}\n >\n <div className=\"liql-logMeta\">\n <span className={`liql-statusTag liql-tag-${levelClass}`}>\n {getIcon(log.level)} {log.level}\n </span>\n <span className=\"liql-logTime\">{formatTime(log.timestamp)}</span>\n </div>\n <div className=\"liql-logContent\">\n {log.title && <strong style={{ color: 'var(--liql-primary)' }}>{log.title}: </strong>}\n {log.message}\n </div>\n\n {isExpanded && (\n <div className=\"liql-expandedContent\">\n {log.stack && (\n <div style={{ color: 'var(--liql-error)', marginBottom: '8px' }}>\n <strong>Stack Trace:</strong>\n <pre style={{ whiteSpace: 'pre-wrap', fontSize: '10px', marginTop: '4px' }}>{log.stack}</pre>\n </div>\n )}\n {log.data && (\n <div>\n <strong>Payload:</strong>\n {renderJson(log.data)}\n </div>\n )}\n {!log.data && !log.stack && <div>Full message: {log.message}</div>}\n </div>\n )}\n </div>\n );\n};\n","import React from 'react';\nimport { Virtuoso } from 'react-virtuoso';\nimport { LogItem } from './LogItem';\nimport { LogEntry } from '../types';\n\ninterface LogListProps {\n logs: LogEntry[];\n filter: string;\n search: string;\n}\n\nexport const LogList: React.FC<LogListProps> = ({ logs, filter, search }) => {\n const filteredLogs = React.useMemo(() => {\n return logs.filter(log => {\n const matchesFilter = filter === 'ALL' || log.level === filter;\n const matchesSearch = search === '' ||\n log.message.toLowerCase().includes(search.toLowerCase()) ||\n (log.title || '').toLowerCase().includes(search.toLowerCase());\n return matchesFilter && matchesSearch;\n }).reverse();\n }, [logs, filter, search]);\n\n return (\n <div className=\"liql-logListContainer\">\n <Virtuoso\n style={{ height: '100%' }}\n data={filteredLogs}\n itemContent={(_index: number, log: LogEntry) => <LogItem key={log.id} log={log} />}\n />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\nimport { LogList } from './LogList';\n\n/**\n * Main 'Liquid Glass' logging console.\n * Contains the log list, filtering, search, and action controls.\n */\nexport const LogPanel: React.FC = () => {\n const { state, setIsPanelOpen, dispatch } = useLoggerContext();\n const [filter, setFilter] = useState('ALL');\n const [search, setSearch] = useState('');\n\n const clearLogs = () => {\n if (confirm('Are you sure you want to clear all logs?')) {\n dispatch({ type: 'CLEAR_LOGS' });\n }\n };\n\n const exportLogs = () => {\n const dataStr = \"data:text/json;charset=utf-8,\" + encodeURIComponent(JSON.stringify(state.logs, null, 2));\n const downloadAnchorNode = document.createElement('a');\n downloadAnchorNode.setAttribute(\"href\", dataStr);\n downloadAnchorNode.setAttribute(\"download\", `logs_${new Date().getTime()}.json`);\n document.body.appendChild(downloadAnchorNode);\n downloadAnchorNode.click();\n downloadAnchorNode.remove();\n };\n\n if (!state) return null;\n\n return (\n <div className=\"liql-panel\">\n <div className=\"liql-panelHeader\">\n <div className=\"liql-titleGroup\">\n <span className=\"liql-title\">ReactLoggerApp console [{state.logs.length}]</span>\n </div>\n <div className=\"liql-controls\">\n <button className=\"liql-btnAction\" onClick={exportLogs} title=\"Export JSON\">📥</button>\n <button className=\"liql-btnAction\" onClick={clearLogs} title=\"Clear Logs\">🗑️</button>\n <button className=\"liql-btnAction\" onClick={() => setIsPanelOpen(false)} title=\"Minimize\">➖</button>\n </div>\n </div>\n\n <div className=\"liql-filterBar\">\n <input\n type=\"text\"\n placeholder=\"Search entries...\"\n className=\"liql-searchInput\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <select\n className=\"liql-selectFilter\"\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n >\n <option value=\"ALL\">ALL</option>\n <option value=\"DEBUG\">DEBUG</option>\n <option value=\"ERROR\">ERROR</option>\n <option value=\"OBJECT\">OBJECTS</option>\n </select>\n </div>\n\n <LogList logs={state.logs} filter={filter} search={search} />\n\n <div className=\"liql-footerActions\">\n <div className=\"liql-storageInfo\">\n {state.config.persistence ? `DRIVER: ${state.config.persistenceDriver?.toUpperCase()}` : 'SESSION MODE'}\n </div>\n <button className=\"liql-btnClose\" onClick={() => setIsPanelOpen(false)}>CLOSE CONSOLE</button>\n </div>\n </div>\n );\n};\n","import React from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\nimport { FloatingButton } from './FloatingButton';\nimport { LogPanel } from './LogPanel';\n\n/**\n * Main entry point for the Logger UI.\n * Renders the floating trigger button and conditionally shows the glass panel.\n * Should be placed at the root level of your application.\n */\nexport const LoggerViewer: React.FC = () => {\n const { isPanelOpen } = useLoggerContext();\n\n return (\n <>\n {!isPanelOpen && <FloatingButton />}\n {isPanelOpen && <LogPanel />}\n </>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/polyfills.ts","#style-inject:#style-inject","../src/styles/logger.css","../src/storage/localStorageDriver.ts","../src/storage/indexedDBDriver.ts","../src/storage/index.ts","../src/Logger.ts","../src/context/LoggerContext.tsx","../src/hooks/useLogger.ts","../src/components/FloatingButton.tsx","../src/components/LogItem.tsx","../src/components/LogList.tsx","../src/components/LogPanel.tsx","../src/components/LoggerViewer.tsx"],"names":["obj","prop","styleInject","css","insertAt","head","style","LocalStorageDriver","key","logs","e","data","DB_NAME","STORE_NAME","DB_VERSION","IndexedDBDriver","openDB","db","tx","store","log","getStorageDriver","type","Logger","dispatch","onLogAdded","level","message","extra","title","err","stack","initialState","loggerReducer","state","action","newLogs","LoggerContext","createContext","LoggerProvider","children","config","useReducer","isPanelOpen","setIsPanelOpen","React","storageRef","useRef","useEffect","loadedLogs","jsx","useLoggerContext","context","useContext","useLogger","debug","useCallback","error","object","clear","exportLogs","dataStr","downloadAnchorNode","FloatingButton","position","setPosition","useState","isDragging","dragOffset","handleMouseDown","rect","handleTouchStart","touch","handleMove","clientX","clientY","nextX","nextY","onMouseMove","onTouchMove","onEnd","handleResize","prev","handleClick","dynamicStyle","LogItem","isExpanded","setIsExpanded","formatTime","isoString","renderJson","getIcon","levelClass","jsxs","LogList","filter","search","filteredLogs","matchesFilter","matchesSearch","Virtuoso","_index","LogPanel","setFilter","setSearch","clearLogs","LoggerViewer","Fragment"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Polyfills for older browsers and Android WebView compatibility\n */\n\n// Polyfill for Object.hasOwn (ES2022)\n// Required for Android WebView < Chrome 93\nif (!Object.hasOwn) {\n Object.hasOwn = function (obj: object, prop: PropertyKey): boolean {\n return Object.prototype.hasOwnProperty.call(obj, prop);\n };\n}\n\nexport { };\n","\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\":root{--liql-primary: #6b21a8;--liql-primary-glow: rgba(107, 33, 168, .5);--liql-error: #ff4d4d;--liql-error-glow: rgba(255, 77, 77, .4);--liql-object: #00ff88;--liql-object-glow: rgba(0, 255, 136, .4);--liql-glass-bg: rgba(15, 23, 42, .9);--liql-glass-border: rgba(255, 255, 255, .1);--liql-glass-edge: rgba(255, 255, 255, .05);--liql-text-main: #f8fafc;--liql-text-muted: #94a3b8;--liql-font-family: \\\"Inter\\\", -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, sans-serif}.liql-floatingButton{position:fixed;right:20px;bottom:20px;width:50px;height:50px;border-radius:50%;background:radial-gradient(circle at 30% 30%,rgba(255,255,255,.15),transparent),linear-gradient(135deg,#6b21a8,#4c1d95);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);box-shadow:0 8px 32px #0006,0 0 15px var(--liql-primary-glow);display:flex;align-items:center;justify-content:center;cursor:grab;z-index:99999;border:1px solid var(--liql-glass-border);transition:all .4s cubic-bezier(.175,.885,.32,1.275);font-size:26px;color:#fff;user-select:none;touch-action:none}.liql-floatingButton:hover{transform:scale(1.1) rotate(5deg);box-shadow:0 12px 40px #00000080,0 0 25px var(--liql-primary-glow)}.liql-badge{position:absolute;top:-2px;right:-2px;background:var(--liql-error);color:#fff;border-radius:12px;min-width:20px;height:20px;padding:0 6px;font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;border:2px solid #0f172a;box-shadow:0 0 10px var(--liql-error-glow)}.liql-panel{position:fixed;background:var(--liql-glass-bg);backdrop-filter:blur(25px) saturate(180%);-webkit-backdrop-filter:blur(25px) saturate(180%);box-shadow:0 20px 50px #0009,inset 0 0 0 1px var(--liql-glass-edge);border:1px solid var(--liql-glass-border);border-radius:20px;display:flex;flex-direction:column;width:440px;height:680px;right:20px;bottom:20px;z-index:999999;overflow:hidden;font-family:var(--liql-font-family);color:var(--liql-text-main);animation:liql-slideUp .4s cubic-bezier(.23,1,.32,1)}.liql-panelHeader{background:#ffffff0d;padding:16px 20px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--liql-glass-border)}.liql-title{font-weight:700;letter-spacing:.5px;text-transform:uppercase;font-size:12px;color:var(--liql-text-muted)}.liql-controls{display:flex;gap:12px}.liql-btnAction{background:#ffffff14;border:1px solid var(--liql-glass-border);color:var(--liql-text-main);width:32px;height:32px;border-radius:8px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.liql-btnAction:hover{background:#ffffff26;transform:translateY(-2px)}.liql-filterBar{padding:12px 20px;display:flex;gap:10px;background:#0003;align-items:center}.liql-searchInput{flex:1;background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px 14px;color:#fff;font-size:13px}.liql-searchInput:focus{outline:none;border-color:var(--liql-primary);background:#ffffff14}.liql-selectFilter{background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px;color:#fff;font-size:12px;cursor:pointer}.liql-logListContainer{flex:1;padding:10px}.liql-logItem{margin-bottom:10px;padding:16px;border-radius:14px;background:#ffffff08;border:1px solid var(--liql-glass-border);transition:all .3s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden}.liql-logItem:hover{background:#ffffff0f;border-color:#fff3;transform:scale(1.01)}.liql-logItem-debug{border-left:4px solid var(--liql-primary)}.liql-logItem-error{border-left:4px solid var(--liql-error);box-shadow:inset 0 0 15px var(--liql-error-glow)}.liql-logItem-object{border-left:4px solid var(--liql-object);box-shadow:inset 0 0 15px var(--liql-object-glow)}.liql-logMeta{display:flex;justify-content:space-between;margin-bottom:8px;font-size:11px;font-weight:500;text-transform:uppercase}.liql-statusTag{padding:2px 8px;border-radius:6px;font-size:9px;font-weight:700}.liql-tag-debug{background:#3498db33;color:#3498db}.liql-tag-error{background:#ff4d4d33;color:#ff4d4d}.liql-tag-object{background:#0f83;color:#0f8}.liql-logTime{color:var(--liql-text-muted)}.liql-logContent{font-size:14px;line-height:1.5;color:#e2e8f0}.liql-expandedContent{margin-top:12px;padding:12px;background:#0000004d;border-radius:10px;font-family:JetBrains Mono,monospace;font-size:12px;border:1px solid var(--liql-glass-border);color:#a5f3fc;overflow-x:auto}.liql-footerActions{padding:14px 20px;background:#0003;display:flex;justify-content:space-between;align-items:center;border-top:1px solid var(--liql-glass-border)}.liql-storageInfo{font-size:10px;color:var(--liql-text-muted)}.liql-btnClose{background:linear-gradient(135deg,var(--liql-primary),#2980b9);border:none;padding:8px 16px;border-radius:8px;color:#fff;font-weight:600;font-size:13px;cursor:pointer;box-shadow:0 4px 12px var(--liql-primary-glow)}@keyframes liql-slideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}@media(max-width:600px){.liql-panel{width:100%!important;height:100%!important;bottom:0!important;right:0!important;left:0!important;border-radius:0;animation:none;background:#0f172a!important;backdrop-filter:none!important;-webkit-backdrop-filter:none!important}}\\n\")","import { LogEntry, StorageDriver } from '../types';\n\nexport class LocalStorageDriver implements StorageDriver {\n private key: string;\n\n constructor(key: string = 'ionic_react_logger_logs') {\n this.key = key;\n }\n\n async save(logs: LogEntry[]): Promise<void> {\n try {\n localStorage.setItem(this.key, JSON.stringify(logs));\n } catch (e) {\n console.error('Failed to save logs to localStorage', e);\n }\n }\n\n async load(): Promise<LogEntry[]> {\n try {\n const data = localStorage.getItem(this.key);\n return data ? JSON.parse(data) : [];\n } catch (e) {\n console.error('Failed to load logs from localStorage', e);\n return [];\n }\n }\n\n async clear(): Promise<void> {\n localStorage.removeItem(this.key);\n }\n}\n","import { openDB, IDBPDatabase } from 'idb';\nimport { LogEntry, StorageDriver } from '../types';\n\nconst DB_NAME = 'IonicReactLoggerDB';\nconst STORE_NAME = 'logs';\nconst DB_VERSION = 1;\n\nexport class IndexedDBDriver implements StorageDriver {\n private dbPromise: Promise<IDBPDatabase>;\n\n constructor() {\n this.dbPromise = openDB(DB_NAME, DB_VERSION, {\n upgrade(db) {\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME, { keyPath: 'id' });\n }\n },\n });\n }\n\n async save(logs: LogEntry[]): Promise<void> {\n const db = await this.dbPromise;\n const tx = db.transaction(STORE_NAME, 'readwrite');\n const store = tx.objectStore(STORE_NAME);\n\n // Clear existing logs first or manage them as needed\n // Simple implementation: clear and re-save everything to match the expected behavior of StorageDriver\n await store.clear();\n for (const log of logs) {\n await store.put(log);\n }\n await tx.done;\n }\n\n async load(): Promise<LogEntry[]> {\n const db = await this.dbPromise;\n return db.getAll(STORE_NAME);\n }\n\n async clear(): Promise<void> {\n const db = await this.dbPromise;\n const tx = db.transaction(STORE_NAME, 'readwrite');\n await tx.objectStore(STORE_NAME).clear();\n await tx.done;\n }\n}\n","import { StorageDriver, LogEntry } from '../types';\nimport { LocalStorageDriver } from './localStorageDriver';\nimport { IndexedDBDriver } from './indexedDBDriver';\n\nexport function getStorageDriver(type: 'localStorage' | 'indexedDB'): StorageDriver {\n if (type === 'indexedDB') {\n return new IndexedDBDriver();\n }\n return new LocalStorageDriver();\n}\n\nexport * from './localStorageDriver';\nexport * from './indexedDBDriver';\n","import { LogEntry, LogLevel } from './types';\n\ntype LoggerDispatch = (action: { type: 'ADD_LOG'; log: LogEntry } | { type: 'CLEAR_LOGS' }) => void;\n\n/**\n * Global Logger class to support logging from plain TypeScript classes\n * and handle early logs before the React Provider is mounted.\n */\nexport class Logger {\n private static dispatch: LoggerDispatch | null = null;\n private static logBuffer: LogEntry[] = [];\n private static onLogAddedCallback?: (log: LogEntry) => void;\n\n /**\n * Internal method to initialize the dispatcher from the React context.\n */\n static _setDispatcher(dispatch: LoggerDispatch, onLogAdded?: (log: LogEntry) => void) {\n this.dispatch = dispatch;\n this.onLogAddedCallback = onLogAdded;\n\n // Flush buffer\n if (this.logBuffer.length > 0) {\n this.logBuffer.forEach(log => {\n this.dispatch!({ type: 'ADD_LOG', log });\n this.onLogAddedCallback?.(log);\n });\n this.logBuffer = [];\n }\n }\n\n private static createLog(level: LogLevel, message: string, extra?: { title?: string, data?: any, stack?: string }): LogEntry {\n return {\n id: Math.random().toString(36).substring(2, 9),\n level,\n message,\n timestamp: new Date().toISOString(),\n ...extra\n };\n }\n\n private static addLog(log: LogEntry) {\n if (this.dispatch) {\n this.dispatch({ type: 'ADD_LOG', log });\n this.onLogAddedCallback?.(log);\n } else {\n this.logBuffer.push(log);\n }\n }\n\n /**\n * Log a debug message (Blue neon)\n */\n static debug(message: string, title?: string) {\n this.addLog(this.createLog('DEBUG', message, { title }));\n }\n\n /**\n * Log an error (Red neon). Supports Error objects for automatic stack trace capture.\n */\n static error(err: string | Error, title?: string) {\n const message = err instanceof Error ? err.message : err;\n const stack = err instanceof Error ? err.stack : undefined;\n this.addLog(this.createLog('ERROR', message, { title: title || 'Error', stack }));\n }\n\n /**\n * Log an object for visualization (Green neon).\n */\n static object(data: any, title?: string) {\n this.addLog(this.createLog('OBJECT', 'Object visualization', { title: title || 'Data Object', data }));\n }\n\n /**\n * Clear all logs.\n */\n static clear() {\n if (this.dispatch) {\n this.dispatch({ type: 'CLEAR_LOGS' });\n } else {\n this.logBuffer = [];\n }\n }\n}\n","import React, { createContext, useContext, useReducer, useEffect, useCallback, useRef } from 'react';\nimport { LogEntry, LogLevel, LoggerConfig, StorageDriver } from '../types';\nimport { getStorageDriver } from '../storage';\nimport { Logger } from '../Logger';\n\ninterface LoggerState {\n logs: LogEntry[];\n config: LoggerConfig;\n unreadCount: number;\n}\n\ntype LoggerAction =\n | { type: 'ADD_LOG'; log: LogEntry }\n | { type: 'SET_LOGS'; logs: LogEntry[] }\n | { type: 'CLEAR_LOGS' }\n | { type: 'SET_CONFIG'; config: Partial<LoggerConfig> }\n | { type: 'RESET_UNREAD' }\n | { type: 'INCREMENT_UNREAD' };\n\nconst initialState: LoggerState = {\n logs: [],\n config: {\n persistence: false,\n persistenceDriver: 'localStorage',\n maxLogs: 500,\n },\n unreadCount: 0,\n};\n\nfunction loggerReducer(state: LoggerState, action: LoggerAction): LoggerState {\n switch (action.type) {\n case 'ADD_LOG': {\n const newLogs = [action.log, ...state.logs].slice(0, state.config.maxLogs);\n return {\n ...state,\n logs: newLogs,\n };\n }\n case 'SET_LOGS':\n return { ...state, logs: [...state.logs, ...action.logs].slice(0, state.config.maxLogs) };\n case 'CLEAR_LOGS':\n return { ...state, logs: [], unreadCount: 0 };\n case 'SET_CONFIG':\n return { ...state, config: { ...state.config, ...action.config } };\n case 'RESET_UNREAD':\n return { ...state, unreadCount: 0 };\n case 'INCREMENT_UNREAD':\n return { ...state, unreadCount: state.unreadCount + 1 };\n default:\n return state;\n }\n}\n\ninterface LoggerContextType {\n state: LoggerState;\n dispatch: React.Dispatch<LoggerAction>;\n isPanelOpen: boolean;\n setIsPanelOpen: (open: boolean) => void;\n}\n\nconst LoggerContext = createContext<LoggerContextType | undefined>(undefined);\n\n/**\n * Provides the logging context to all child components.\n * This should wrap your entire application (e.g. in App.tsx).\n * \n * @param config Optional initial configuration for persistence and limits.\n */\nexport const LoggerProvider: React.FC<{ children: React.ReactNode; config?: LoggerConfig }> = ({\n children,\n config,\n}) => {\n const [state, dispatch] = useReducer(loggerReducer, {\n ...initialState,\n config: { ...initialState.config, ...config },\n });\n const [isPanelOpen, setIsPanelOpen] = React.useState(false);\n const storageRef = useRef<StorageDriver | null>(null);\n\n // Initialize storage driver and Logger singleton\n useEffect(() => {\n Logger._setDispatcher(dispatch, state.config.onLogAdded);\n\n if (state.config.persistence) {\n storageRef.current = getStorageDriver(state.config.persistenceDriver || 'localStorage');\n storageRef.current.load().then((loadedLogs) => {\n dispatch({ type: 'SET_LOGS', logs: loadedLogs });\n });\n }\n }, [state.config.persistence, state.config.persistenceDriver]);\n\n // Persist logs when they change\n useEffect(() => {\n if (state.config.persistence && storageRef.current) {\n storageRef.current.save(state.logs);\n }\n }, [state.logs, state.config.persistence]);\n\n return (\n <LoggerContext.Provider value={{ state, dispatch, isPanelOpen, setIsPanelOpen }}>\n {children}\n </LoggerContext.Provider>\n );\n};\n\n/**\n * Internal hook to access the logger context state.\n * Use the public `useLogger` hook for standard logging operations.\n */\nexport const useLoggerContext = () => {\n const context = useContext(LoggerContext);\n if (!context) {\n throw new Error('useLoggerContext must be used within a LoggerProvider');\n }\n return context;\n};\n","import { useCallback } from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\nimport { Logger } from '../Logger';\n\n/**\n * Main hook to interact with the Liquid Glass Logger.\n * \n * Provides methods for different logging levels and allows accessing\n * the current state of logs.\n * \n * @example\n * ```tsx\n * const { debug, error, object } = useLogger();\n * \n * debug('App started');\n * error(new Error('Failed to fetch'), 'API Error');\n * object({ user: 'John' }, 'Current User');\n * ```\n */\nexport const useLogger = () => {\n const { state } = useLoggerContext();\n\n /**\n * Log a debug message (Blue neon)\n */\n const debug = useCallback((message: string, title?: string) => {\n Logger.debug(message, title);\n }, []);\n\n /**\n * Log an error. If an Error object is passed, it automatically captures the stack trace.\n * (Red neon)\n */\n const error = useCallback((err: string | Error, title?: string) => {\n Logger.error(err, title);\n }, []);\n\n /**\n * Log a data object for inspection.\n * (Green neon)\n */\n const object = useCallback((data: any, title?: string) => {\n Logger.object(data, title);\n }, []);\n\n /**\n * Clears all logs from the current session and persistent storage.\n */\n const clear = useCallback(() => {\n Logger.clear();\n }, []);\n\n /**\n * Exports all logs as a JSON file download.\n */\n const exportLogs = useCallback(() => {\n const dataStr = \"data:text/json;charset=utf-8,\" + encodeURIComponent(JSON.stringify(state.logs, null, 2));\n const downloadAnchorNode = document.createElement('a');\n downloadAnchorNode.setAttribute(\"href\", dataStr);\n downloadAnchorNode.setAttribute(\"download\", `logs_${new Date().getTime()}.json`);\n document.body.appendChild(downloadAnchorNode);\n downloadAnchorNode.click();\n downloadAnchorNode.remove();\n }, [state.logs]);\n\n return {\n /** Register a debug message */\n debug,\n /** Register an error or exception */\n error,\n /** Register an object for JSON visualization */\n object,\n /** Clear all history */\n clear,\n /** Download history as JSON */\n exportLogs,\n /** List of all captured logs */\n logs: state.logs,\n /** Count of logs not yet viewed */\n unreadCount: state.unreadCount,\n };\n};\n","import React, { useState, useRef, useEffect, useCallback } from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\n\n/**\n * Draggable floating trigger button.\n * Uses hybrid positioning (CSS initial + JS drag) for maximum compatibility.\n */\nexport const FloatingButton: React.FC = () => {\n const { state, setIsPanelOpen } = useLoggerContext();\n\n // Default to null to use CSS positioning initially\n const [position, setPosition] = useState<{ x: number; y: number } | null>(null);\n const isDragging = useRef(false);\n const dragOffset = useRef({ x: 0, y: 0 });\n\n const handleMouseDown = (e: React.MouseEvent) => {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n isDragging.current = true;\n dragOffset.current = {\n x: e.clientX - rect.left,\n y: e.clientY - rect.top\n };\n };\n\n const handleTouchStart = (e: React.TouchEvent) => {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n isDragging.current = true;\n const touch = e.touches[0];\n dragOffset.current = {\n x: touch.clientX - rect.left,\n y: touch.clientY - rect.top\n };\n };\n\n const handleMove = useCallback((clientX: number, clientY: number) => {\n if (!isDragging.current) return;\n\n // Keep button within viewport\n const nextX = Math.max(10, Math.min(window.innerWidth - 60, clientX - dragOffset.current.x));\n const nextY = Math.max(10, Math.min(window.innerHeight - 60, clientY - dragOffset.current.y));\n\n setPosition({ x: nextX, y: nextY });\n }, []);\n\n useEffect(() => {\n const onMouseMove = (e: MouseEvent) => handleMove(e.clientX, e.clientY);\n const onTouchMove = (e: TouchEvent) => handleMove(e.touches[0].clientX, e.touches[0].clientY);\n const onEnd = () => {\n isDragging.current = false;\n };\n\n window.addEventListener('mousemove', onMouseMove);\n window.addEventListener('touchmove', onTouchMove, { passive: false });\n window.addEventListener('mouseup', onEnd);\n window.addEventListener('touchend', onEnd);\n\n return () => {\n window.removeEventListener('mousemove', onMouseMove);\n window.removeEventListener('touchmove', onTouchMove);\n window.removeEventListener('mouseup', onEnd);\n window.removeEventListener('touchend', onEnd);\n };\n }, [handleMove]);\n\n // Handle window resize to keep button in bounds\n useEffect(() => {\n const handleResize = () => {\n if (position) {\n setPosition(prev => {\n if (!prev) return null;\n return {\n x: Math.min(prev.x, window.innerWidth - 60),\n y: Math.min(prev.y, window.innerHeight - 60)\n };\n });\n }\n };\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, [position]);\n\n const handleClick = () => {\n if (isDragging.current) return;\n setIsPanelOpen(true);\n };\n\n // If never moved, let CSS handle it. If moved, use absolute pixel coordinates.\n const dynamicStyle: React.CSSProperties = position\n ? { left: `${position.x}px`, top: `${position.y}px`, right: 'auto', bottom: 'auto' }\n : {};\n\n return (\n <div\n className=\"liql-floatingButton\"\n style={dynamicStyle}\n onMouseDown={handleMouseDown}\n onTouchStart={handleTouchStart}\n onClick={handleClick}\n aria-label=\"Open Logger\"\n >\n {state.unreadCount > 0 && (\n <div className=\"liql-badge\">{state.unreadCount}</div>\n )}\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport { LogEntry } from '../types';\n\ninterface LogItemProps {\n log: LogEntry;\n}\n\nexport const LogItem: React.FC<LogItemProps> = ({ log }) => {\n const [isExpanded, setIsExpanded] = useState(false);\n\n const formatTime = (isoString: string) => {\n const date = new Date(isoString);\n return date.toTimeString().split(' ')[0];\n };\n\n const renderJson = (data: any) => {\n try {\n return (\n <pre className=\"liql-expandedContent\">\n {JSON.stringify(data, null, 2)}\n </pre>\n );\n } catch (e) {\n return <div>Error parsing object</div>;\n }\n };\n\n const getIcon = (level: string) => {\n switch (level) {\n case 'DEBUG': return '🐞';\n case 'ERROR': return '❌';\n case 'OBJECT': return '📦';\n default: return '📝';\n }\n };\n\n const levelClass = log.level.toLowerCase();\n\n return (\n <div\n className={`liql-logItem liql-logItem-${levelClass}`}\n onClick={() => setIsExpanded(!isExpanded)}\n >\n <div className=\"liql-logMeta\">\n <span className={`liql-statusTag liql-tag-${levelClass}`}>\n {getIcon(log.level)} {log.level}\n </span>\n <span className=\"liql-logTime\">{formatTime(log.timestamp)}</span>\n </div>\n <div className=\"liql-logContent\">\n {log.title && <strong style={{ color: 'var(--liql-primary)' }}>{log.title}: </strong>}\n {log.message}\n </div>\n\n {isExpanded && (\n <div className=\"liql-expandedContent\">\n {log.stack && (\n <div style={{ color: 'var(--liql-error)', marginBottom: '8px' }}>\n <strong>Stack Trace:</strong>\n <pre style={{ whiteSpace: 'pre-wrap', fontSize: '10px', marginTop: '4px' }}>{log.stack}</pre>\n </div>\n )}\n {log.data && (\n <div>\n <strong>Payload:</strong>\n {renderJson(log.data)}\n </div>\n )}\n {!log.data && !log.stack && <div>Full message: {log.message}</div>}\n </div>\n )}\n </div>\n );\n};\n","import React from 'react';\nimport { Virtuoso } from 'react-virtuoso';\nimport { LogItem } from './LogItem';\nimport { LogEntry } from '../types';\n\ninterface LogListProps {\n logs: LogEntry[];\n filter: string;\n search: string;\n}\n\nexport const LogList: React.FC<LogListProps> = ({ logs, filter, search }) => {\n const filteredLogs = React.useMemo(() => {\n return logs.filter(log => {\n const matchesFilter = filter === 'ALL' || log.level === filter;\n const matchesSearch = search === '' ||\n log.message.toLowerCase().includes(search.toLowerCase()) ||\n (log.title || '').toLowerCase().includes(search.toLowerCase());\n return matchesFilter && matchesSearch;\n }).reverse();\n }, [logs, filter, search]);\n\n return (\n <div className=\"liql-logListContainer\">\n <Virtuoso\n style={{ height: '100%' }}\n data={filteredLogs}\n itemContent={(_index: number, log: LogEntry) => <LogItem key={log.id} log={log} />}\n />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\nimport { LogList } from './LogList';\n\n/**\n * Main 'Liquid Glass' logging console.\n * Contains the log list, filtering, search, and action controls.\n */\nexport const LogPanel: React.FC = () => {\n const { state, setIsPanelOpen, dispatch } = useLoggerContext();\n const [filter, setFilter] = useState('ALL');\n const [search, setSearch] = useState('');\n\n const clearLogs = () => {\n if (confirm('Are you sure you want to clear all logs?')) {\n dispatch({ type: 'CLEAR_LOGS' });\n }\n };\n\n const exportLogs = () => {\n const dataStr = \"data:text/json;charset=utf-8,\" + encodeURIComponent(JSON.stringify(state.logs, null, 2));\n const downloadAnchorNode = document.createElement('a');\n downloadAnchorNode.setAttribute(\"href\", dataStr);\n downloadAnchorNode.setAttribute(\"download\", `logs_${new Date().getTime()}.json`);\n document.body.appendChild(downloadAnchorNode);\n downloadAnchorNode.click();\n downloadAnchorNode.remove();\n };\n\n if (!state) return null;\n\n return (\n <div className=\"liql-panel\">\n <div className=\"liql-panelHeader\">\n <div className=\"liql-titleGroup\">\n <span className=\"liql-title\">ReactLoggerApp console [{state.logs.length}]</span>\n </div>\n <div className=\"liql-controls\">\n <button className=\"liql-btnAction\" onClick={exportLogs} title=\"Export JSON\">📥</button>\n <button className=\"liql-btnAction\" onClick={clearLogs} title=\"Clear Logs\">🗑️</button>\n <button className=\"liql-btnAction\" onClick={() => setIsPanelOpen(false)} title=\"Minimize\">➖</button>\n </div>\n </div>\n\n <div className=\"liql-filterBar\">\n <input\n type=\"text\"\n placeholder=\"Search entries...\"\n className=\"liql-searchInput\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <select\n className=\"liql-selectFilter\"\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n >\n <option value=\"ALL\">ALL</option>\n <option value=\"DEBUG\">DEBUG</option>\n <option value=\"ERROR\">ERROR</option>\n <option value=\"OBJECT\">OBJECTS</option>\n </select>\n </div>\n\n <LogList logs={state.logs} filter={filter} search={search} />\n\n <div className=\"liql-footerActions\">\n <div className=\"liql-storageInfo\">\n {state.config.persistence ? `DRIVER: ${state.config.persistenceDriver?.toUpperCase()}` : 'SESSION MODE'}\n </div>\n <button className=\"liql-btnClose\" onClick={() => setIsPanelOpen(false)}>CLOSE CONSOLE</button>\n </div>\n </div>\n );\n};\n","import React from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\nimport { FloatingButton } from './FloatingButton';\nimport { LogPanel } from './LogPanel';\n\n/**\n * Main entry point for the Logger UI.\n * Renders the floating trigger button and conditionally shows the glass panel.\n * Should be placed at the root level of your application.\n */\nexport const LoggerViewer: React.FC = () => {\n const { isPanelOpen } = useLoggerContext();\n\n return (\n <>\n {!isPanelOpen && <FloatingButton />}\n {isPanelOpen && <LogPanel />}\n </>\n );\n};\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import U,{createContext,useReducer,useRef,useEffect,useContext,useCallback,useState}from'react';import {openDB}from'idb';import {jsx,jsxs,Fragment}from'react/jsx-runtime';import {Virtuoso}from'react-virtuoso';function C(e,{insertAt:t}={}){if(typeof document>"u")return;let o=document.head||document.getElementsByTagName("head")[0],r=document.createElement("style");r.type="text/css",t==="top"&&o.firstChild?o.insertBefore(r,o.firstChild):o.appendChild(r),r.styleSheet?r.styleSheet.cssText=e:r.appendChild(document.createTextNode(e));}C(`:root{--liql-primary: #6b21a8;--liql-primary-glow: rgba(107, 33, 168, .5);--liql-error: #ff4d4d;--liql-error-glow: rgba(255, 77, 77, .4);--liql-object: #00ff88;--liql-object-glow: rgba(0, 255, 136, .4);--liql-glass-bg: rgba(15, 23, 42, .9);--liql-glass-border: rgba(255, 255, 255, .1);--liql-glass-edge: rgba(255, 255, 255, .05);--liql-text-main: #f8fafc;--liql-text-muted: #94a3b8;--liql-font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif}.liql-floatingButton{position:fixed;right:20px;bottom:20px;width:50px;height:50px;border-radius:50%;background:radial-gradient(circle at 30% 30%,rgba(255,255,255,.15),transparent),linear-gradient(135deg,#6b21a8,#4c1d95);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);box-shadow:0 8px 32px #0006,0 0 15px var(--liql-primary-glow);display:flex;align-items:center;justify-content:center;cursor:grab;z-index:99999;border:1px solid var(--liql-glass-border);transition:all .4s cubic-bezier(.175,.885,.32,1.275);font-size:26px;color:#fff;user-select:none;touch-action:none}.liql-floatingButton:hover{transform:scale(1.1) rotate(5deg);box-shadow:0 12px 40px #00000080,0 0 25px var(--liql-primary-glow)}.liql-badge{position:absolute;top:-2px;right:-2px;background:var(--liql-error);color:#fff;border-radius:12px;min-width:20px;height:20px;padding:0 6px;font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;border:2px solid #0f172a;box-shadow:0 0 10px var(--liql-error-glow)}.liql-panel{position:fixed;background:var(--liql-glass-bg);backdrop-filter:blur(25px) saturate(180%);-webkit-backdrop-filter:blur(25px) saturate(180%);box-shadow:0 20px 50px #0009,inset 0 0 0 1px var(--liql-glass-edge);border:1px solid var(--liql-glass-border);border-radius:20px;display:flex;flex-direction:column;width:440px;height:680px;right:20px;bottom:20px;z-index:999999;overflow:hidden;font-family:var(--liql-font-family);color:var(--liql-text-main);animation:liql-slideUp .4s cubic-bezier(.23,1,.32,1)}.liql-panelHeader{background:#ffffff0d;padding:16px 20px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--liql-glass-border)}.liql-title{font-weight:700;letter-spacing:.5px;text-transform:uppercase;font-size:12px;color:var(--liql-text-muted)}.liql-controls{display:flex;gap:12px}.liql-btnAction{background:#ffffff14;border:1px solid var(--liql-glass-border);color:var(--liql-text-main);width:32px;height:32px;border-radius:8px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.liql-btnAction:hover{background:#ffffff26;transform:translateY(-2px)}.liql-filterBar{padding:12px 20px;display:flex;gap:10px;background:#0003;align-items:center}.liql-searchInput{flex:1;background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px 14px;color:#fff;font-size:13px}.liql-searchInput:focus{outline:none;border-color:var(--liql-primary);background:#ffffff14}.liql-selectFilter{background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px;color:#fff;font-size:12px;cursor:pointer}.liql-logListContainer{flex:1;padding:10px}.liql-logItem{margin-bottom:10px;padding:16px;border-radius:14px;background:#ffffff08;border:1px solid var(--liql-glass-border);transition:all .3s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden}.liql-logItem:hover{background:#ffffff0f;border-color:#fff3;transform:scale(1.01)}.liql-logItem-debug{border-left:4px solid var(--liql-primary)}.liql-logItem-error{border-left:4px solid var(--liql-error);box-shadow:inset 0 0 15px var(--liql-error-glow)}.liql-logItem-object{border-left:4px solid var(--liql-object);box-shadow:inset 0 0 15px var(--liql-object-glow)}.liql-logMeta{display:flex;justify-content:space-between;margin-bottom:8px;font-size:11px;font-weight:500;text-transform:uppercase}.liql-statusTag{padding:2px 8px;border-radius:6px;font-size:9px;font-weight:700}.liql-tag-debug{background:#3498db33;color:#3498db}.liql-tag-error{background:#ff4d4d33;color:#ff4d4d}.liql-tag-object{background:#0f83;color:#0f8}.liql-logTime{color:var(--liql-text-muted)}.liql-logContent{font-size:14px;line-height:1.5;color:#e2e8f0}.liql-expandedContent{margin-top:12px;padding:12px;background:#0000004d;border-radius:10px;font-family:JetBrains Mono,monospace;font-size:12px;border:1px solid var(--liql-glass-border);color:#a5f3fc;overflow-x:auto}.liql-footerActions{padding:14px 20px;background:#0003;display:flex;justify-content:space-between;align-items:center;border-top:1px solid var(--liql-glass-border)}.liql-storageInfo{font-size:10px;color:var(--liql-text-muted)}.liql-btnClose{background:linear-gradient(135deg,var(--liql-primary),#2980b9);border:none;padding:8px 16px;border-radius:8px;color:#fff;font-weight:600;font-size:13px;cursor:pointer;box-shadow:0 4px 12px var(--liql-primary-glow)}@keyframes liql-slideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}@media(max-width:600px){.liql-panel{width:100%!important;height:100%!important;bottom:0!important;right:0!important;left:0!important;border-radius:0;animation:none;background:#0f172a!important;backdrop-filter:none!important;-webkit-backdrop-filter:none!important}}
|
|
2
|
-
`);var
|
|
1
|
+
import U,{createContext,useReducer,useRef,useEffect,useContext,useCallback,useState}from'react';import {openDB}from'idb';import {jsx,jsxs,Fragment}from'react/jsx-runtime';import {Virtuoso}from'react-virtuoso';Object.hasOwn||(Object.hasOwn=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)});function C(e,{insertAt:t}={}){if(typeof document>"u")return;let o=document.head||document.getElementsByTagName("head")[0],r=document.createElement("style");r.type="text/css",t==="top"&&o.firstChild?o.insertBefore(r,o.firstChild):o.appendChild(r),r.styleSheet?r.styleSheet.cssText=e:r.appendChild(document.createTextNode(e));}C(`:root{--liql-primary: #6b21a8;--liql-primary-glow: rgba(107, 33, 168, .5);--liql-error: #ff4d4d;--liql-error-glow: rgba(255, 77, 77, .4);--liql-object: #00ff88;--liql-object-glow: rgba(0, 255, 136, .4);--liql-glass-bg: rgba(15, 23, 42, .9);--liql-glass-border: rgba(255, 255, 255, .1);--liql-glass-edge: rgba(255, 255, 255, .05);--liql-text-main: #f8fafc;--liql-text-muted: #94a3b8;--liql-font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif}.liql-floatingButton{position:fixed;right:20px;bottom:20px;width:50px;height:50px;border-radius:50%;background:radial-gradient(circle at 30% 30%,rgba(255,255,255,.15),transparent),linear-gradient(135deg,#6b21a8,#4c1d95);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);box-shadow:0 8px 32px #0006,0 0 15px var(--liql-primary-glow);display:flex;align-items:center;justify-content:center;cursor:grab;z-index:99999;border:1px solid var(--liql-glass-border);transition:all .4s cubic-bezier(.175,.885,.32,1.275);font-size:26px;color:#fff;user-select:none;touch-action:none}.liql-floatingButton:hover{transform:scale(1.1) rotate(5deg);box-shadow:0 12px 40px #00000080,0 0 25px var(--liql-primary-glow)}.liql-badge{position:absolute;top:-2px;right:-2px;background:var(--liql-error);color:#fff;border-radius:12px;min-width:20px;height:20px;padding:0 6px;font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;border:2px solid #0f172a;box-shadow:0 0 10px var(--liql-error-glow)}.liql-panel{position:fixed;background:var(--liql-glass-bg);backdrop-filter:blur(25px) saturate(180%);-webkit-backdrop-filter:blur(25px) saturate(180%);box-shadow:0 20px 50px #0009,inset 0 0 0 1px var(--liql-glass-edge);border:1px solid var(--liql-glass-border);border-radius:20px;display:flex;flex-direction:column;width:440px;height:680px;right:20px;bottom:20px;z-index:999999;overflow:hidden;font-family:var(--liql-font-family);color:var(--liql-text-main);animation:liql-slideUp .4s cubic-bezier(.23,1,.32,1)}.liql-panelHeader{background:#ffffff0d;padding:16px 20px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--liql-glass-border)}.liql-title{font-weight:700;letter-spacing:.5px;text-transform:uppercase;font-size:12px;color:var(--liql-text-muted)}.liql-controls{display:flex;gap:12px}.liql-btnAction{background:#ffffff14;border:1px solid var(--liql-glass-border);color:var(--liql-text-main);width:32px;height:32px;border-radius:8px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.liql-btnAction:hover{background:#ffffff26;transform:translateY(-2px)}.liql-filterBar{padding:12px 20px;display:flex;gap:10px;background:#0003;align-items:center}.liql-searchInput{flex:1;background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px 14px;color:#fff;font-size:13px}.liql-searchInput:focus{outline:none;border-color:var(--liql-primary);background:#ffffff14}.liql-selectFilter{background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px;color:#fff;font-size:12px;cursor:pointer}.liql-logListContainer{flex:1;padding:10px}.liql-logItem{margin-bottom:10px;padding:16px;border-radius:14px;background:#ffffff08;border:1px solid var(--liql-glass-border);transition:all .3s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden}.liql-logItem:hover{background:#ffffff0f;border-color:#fff3;transform:scale(1.01)}.liql-logItem-debug{border-left:4px solid var(--liql-primary)}.liql-logItem-error{border-left:4px solid var(--liql-error);box-shadow:inset 0 0 15px var(--liql-error-glow)}.liql-logItem-object{border-left:4px solid var(--liql-object);box-shadow:inset 0 0 15px var(--liql-object-glow)}.liql-logMeta{display:flex;justify-content:space-between;margin-bottom:8px;font-size:11px;font-weight:500;text-transform:uppercase}.liql-statusTag{padding:2px 8px;border-radius:6px;font-size:9px;font-weight:700}.liql-tag-debug{background:#3498db33;color:#3498db}.liql-tag-error{background:#ff4d4d33;color:#ff4d4d}.liql-tag-object{background:#0f83;color:#0f8}.liql-logTime{color:var(--liql-text-muted)}.liql-logContent{font-size:14px;line-height:1.5;color:#e2e8f0}.liql-expandedContent{margin-top:12px;padding:12px;background:#0000004d;border-radius:10px;font-family:JetBrains Mono,monospace;font-size:12px;border:1px solid var(--liql-glass-border);color:#a5f3fc;overflow-x:auto}.liql-footerActions{padding:14px 20px;background:#0003;display:flex;justify-content:space-between;align-items:center;border-top:1px solid var(--liql-glass-border)}.liql-storageInfo{font-size:10px;color:var(--liql-text-muted)}.liql-btnClose{background:linear-gradient(135deg,var(--liql-primary),#2980b9);border:none;padding:8px 16px;border-radius:8px;color:#fff;font-weight:600;font-size:13px;cursor:pointer;box-shadow:0 4px 12px var(--liql-primary-glow)}@keyframes liql-slideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}@media(max-width:600px){.liql-panel{width:100%!important;height:100%!important;bottom:0!important;right:0!important;left:0!important;border-radius:0;animation:none;background:#0f172a!important;backdrop-filter:none!important;-webkit-backdrop-filter:none!important}}
|
|
2
|
+
`);var q=class{key;constructor(t="ionic_react_logger_logs"){this.key=t;}async save(t){try{localStorage.setItem(this.key,JSON.stringify(t));}catch(o){console.error("Failed to save logs to localStorage",o);}}async load(){try{let t=localStorage.getItem(this.key);return t?JSON.parse(t):[]}catch(t){return console.error("Failed to load logs from localStorage",t),[]}}async clear(){localStorage.removeItem(this.key);}};var G="IonicReactLoggerDB",v="logs",F=1,E=class{dbPromise;constructor(){this.dbPromise=openDB(G,F,{upgrade(t){t.objectStoreNames.contains(v)||t.createObjectStore(v,{keyPath:"id"});}});}async save(t){let r=(await this.dbPromise).transaction(v,"readwrite"),i=r.objectStore(v);await i.clear();for(let s of t)await i.put(s);await r.done;}async load(){return (await this.dbPromise).getAll(v)}async clear(){let o=(await this.dbPromise).transaction(v,"readwrite");await o.objectStore(v).clear(),await o.done;}};function k(e){return e==="indexedDB"?new E:new q}var p=class{static dispatch=null;static logBuffer=[];static onLogAddedCallback;static _setDispatcher(t,o){this.dispatch=t,this.onLogAddedCallback=o,this.logBuffer.length>0&&(this.logBuffer.forEach(r=>{this.dispatch({type:"ADD_LOG",log:r}),this.onLogAddedCallback?.(r);}),this.logBuffer=[]);}static createLog(t,o,r){return {id:Math.random().toString(36).substring(2,9),level:t,message:o,timestamp:new Date().toISOString(),...r}}static addLog(t){this.dispatch?(this.dispatch({type:"ADD_LOG",log:t}),this.onLogAddedCallback?.(t)):this.logBuffer.push(t);}static debug(t,o){this.addLog(this.createLog("DEBUG",t,{title:o}));}static error(t,o){let r=t instanceof Error?t.message:t,i=t instanceof Error?t.stack:void 0;this.addLog(this.createLog("ERROR",r,{title:o||"Error",stack:i}));}static object(t,o){this.addLog(this.createLog("OBJECT","Object visualization",{title:o||"Data Object",data:t}));}static clear(){this.dispatch?this.dispatch({type:"CLEAR_LOGS"}):this.logBuffer=[];}};var D={logs:[],config:{persistence:false,persistenceDriver:"localStorage",maxLogs:500},unreadCount:0};function X(e,t){switch(t.type){case "ADD_LOG":{let o=[t.log,...e.logs].slice(0,e.config.maxLogs);return {...e,logs:o}}case "SET_LOGS":return {...e,logs:[...e.logs,...t.logs].slice(0,e.config.maxLogs)};case "CLEAR_LOGS":return {...e,logs:[],unreadCount:0};case "SET_CONFIG":return {...e,config:{...e.config,...t.config}};case "RESET_UNREAD":return {...e,unreadCount:0};case "INCREMENT_UNREAD":return {...e,unreadCount:e.unreadCount+1};default:return e}}var O=createContext(void 0),ve=({children:e,config:t})=>{let[o,r]=useReducer(X,{...D,config:{...D.config,...t}}),[i,s]=U.useState(false),a=useRef(null);return useEffect(()=>{p._setDispatcher(r,o.config.onLogAdded),o.config.persistence&&(a.current=k(o.config.persistenceDriver||"localStorage"),a.current.load().then(n=>{r({type:"SET_LOGS",logs:n});}));},[o.config.persistence,o.config.persistenceDriver]),useEffect(()=>{o.config.persistence&&a.current&&a.current.save(o.logs);},[o.logs,o.config.persistence]),jsx(O.Provider,{value:{state:o,dispatch:r,isPanelOpen:i,setIsPanelOpen:s},children:e})},u=()=>{let e=useContext(O);if(!e)throw new Error("useLoggerContext must be used within a LoggerProvider");return e};var Ce=()=>{let{state:e}=u(),t=useCallback((a,n)=>{p.debug(a,n);},[]),o=useCallback((a,n)=>{p.error(a,n);},[]),r=useCallback((a,n)=>{p.object(a,n);},[]),i=useCallback(()=>{p.clear();},[]),s=useCallback(()=>{let a="data:text/json;charset=utf-8,"+encodeURIComponent(JSON.stringify(e.logs,null,2)),n=document.createElement("a");n.setAttribute("href",a),n.setAttribute("download",`logs_${new Date().getTime()}.json`),document.body.appendChild(n),n.click(),n.remove();},[e.logs]);return {debug:t,error:o,object:r,clear:i,exportLogs:s,logs:e.logs,unreadCount:e.unreadCount}};var P=()=>{let{state:e,setIsPanelOpen:t}=u(),[o,r]=useState(null),i=useRef(false),s=useRef({x:0,y:0}),a=l=>{let c=l.currentTarget.getBoundingClientRect();i.current=true,s.current={x:l.clientX-c.left,y:l.clientY-c.top};},n=l=>{let c=l.currentTarget.getBoundingClientRect();i.current=true;let g=l.touches[0];s.current={x:g.clientX-c.left,y:g.clientY-c.top};},m=useCallback((l,c)=>{if(!i.current)return;let g=Math.max(10,Math.min(window.innerWidth-60,l-s.current.x)),h=Math.max(10,Math.min(window.innerHeight-60,c-s.current.y));r({x:g,y:h});},[]);useEffect(()=>{let l=h=>m(h.clientX,h.clientY),c=h=>m(h.touches[0].clientX,h.touches[0].clientY),g=()=>{i.current=false;};return window.addEventListener("mousemove",l),window.addEventListener("touchmove",c,{passive:false}),window.addEventListener("mouseup",g),window.addEventListener("touchend",g),()=>{window.removeEventListener("mousemove",l),window.removeEventListener("touchmove",c),window.removeEventListener("mouseup",g),window.removeEventListener("touchend",g);}},[m]),useEffect(()=>{let l=()=>{o&&r(c=>c?{x:Math.min(c.x,window.innerWidth-60),y:Math.min(c.y,window.innerHeight-60)}:null);};return window.addEventListener("resize",l),()=>window.removeEventListener("resize",l)},[o]);let x=()=>{i.current||t(true);},b=o?{left:`${o.x}px`,top:`${o.y}px`,right:"auto",bottom:"auto"}:{};return jsx("div",{className:"liql-floatingButton",style:b,onMouseDown:a,onTouchStart:n,onClick:x,"aria-label":"Open Logger",children:e.unreadCount>0&&jsx("div",{className:"liql-badge",children:e.unreadCount})})};var T=({log:e})=>{let[t,o]=useState(false),r=n=>new Date(n).toTimeString().split(" ")[0],i=n=>{try{return jsx("pre",{className:"liql-expandedContent",children:JSON.stringify(n,null,2)})}catch{return jsx("div",{children:"Error parsing object"})}},s=n=>{switch(n){case "DEBUG":return "\u{1F41E}";case "ERROR":return "\u274C";case "OBJECT":return "\u{1F4E6}";default:return "\u{1F4DD}"}},a=e.level.toLowerCase();return jsxs("div",{className:`liql-logItem liql-logItem-${a}`,onClick:()=>o(!t),children:[jsxs("div",{className:"liql-logMeta",children:[jsxs("span",{className:`liql-statusTag liql-tag-${a}`,children:[s(e.level)," ",e.level]}),jsx("span",{className:"liql-logTime",children:r(e.timestamp)})]}),jsxs("div",{className:"liql-logContent",children:[e.title&&jsxs("strong",{style:{color:"var(--liql-primary)"},children:[e.title,": "]}),e.message]}),t&&jsxs("div",{className:"liql-expandedContent",children:[e.stack&&jsxs("div",{style:{color:"var(--liql-error)",marginBottom:"8px"},children:[jsx("strong",{children:"Stack Trace:"}),jsx("pre",{style:{whiteSpace:"pre-wrap",fontSize:"10px",marginTop:"4px"},children:e.stack})]}),e.data&&jsxs("div",{children:[jsx("strong",{children:"Payload:"}),i(e.data)]}),!e.data&&!e.stack&&jsxs("div",{children:["Full message: ",e.message]})]})]})};var B=({logs:e,filter:t,search:o})=>{let r=U.useMemo(()=>e.filter(i=>{let s=t==="ALL"||i.level===t,a=o===""||i.message.toLowerCase().includes(o.toLowerCase())||(i.title||"").toLowerCase().includes(o.toLowerCase());return s&&a}).reverse(),[e,t,o]);return jsx("div",{className:"liql-logListContainer",children:jsx(Virtuoso,{style:{height:"100%"},data:r,itemContent:(i,s)=>jsx(T,{log:s},s.id)})})};var M=()=>{let{state:e,setIsPanelOpen:t,dispatch:o}=u(),[r,i]=useState("ALL"),[s,a]=useState(""),n=()=>{confirm("Are you sure you want to clear all logs?")&&o({type:"CLEAR_LOGS"});},m=()=>{let x="data:text/json;charset=utf-8,"+encodeURIComponent(JSON.stringify(e.logs,null,2)),b=document.createElement("a");b.setAttribute("href",x),b.setAttribute("download",`logs_${new Date().getTime()}.json`),document.body.appendChild(b),b.click(),b.remove();};return e?jsxs("div",{className:"liql-panel",children:[jsxs("div",{className:"liql-panelHeader",children:[jsx("div",{className:"liql-titleGroup",children:jsxs("span",{className:"liql-title",children:["ReactLoggerApp console [",e.logs.length,"]"]})}),jsxs("div",{className:"liql-controls",children:[jsx("button",{className:"liql-btnAction",onClick:m,title:"Export JSON",children:"\u{1F4E5}"}),jsx("button",{className:"liql-btnAction",onClick:n,title:"Clear Logs",children:"\u{1F5D1}\uFE0F"}),jsx("button",{className:"liql-btnAction",onClick:()=>t(false),title:"Minimize",children:"\u2796"})]})]}),jsxs("div",{className:"liql-filterBar",children:[jsx("input",{type:"text",placeholder:"Search entries...",className:"liql-searchInput",value:s,onChange:x=>a(x.target.value)}),jsxs("select",{className:"liql-selectFilter",value:r,onChange:x=>i(x.target.value),children:[jsx("option",{value:"ALL",children:"ALL"}),jsx("option",{value:"DEBUG",children:"DEBUG"}),jsx("option",{value:"ERROR",children:"ERROR"}),jsx("option",{value:"OBJECT",children:"OBJECTS"})]})]}),jsx(B,{logs:e.logs,filter:r,search:s}),jsxs("div",{className:"liql-footerActions",children:[jsx("div",{className:"liql-storageInfo",children:e.config.persistence?`DRIVER: ${e.config.persistenceDriver?.toUpperCase()}`:"SESSION MODE"}),jsx("button",{className:"liql-btnClose",onClick:()=>t(false),children:"CLOSE CONSOLE"})]})]}):null};var We=()=>{let{isPanelOpen:e}=u();return jsxs(Fragment,{children:[!e&&jsx(P,{}),e&&jsx(M,{})]})};export{p as Logger,ve as LoggerProvider,We as LoggerViewer,Ce as useLogger,u as useLoggerContext};//# sourceMappingURL=index.mjs.map
|
|
3
3
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["#style-inject:#style-inject","../src/styles/logger.css","../src/storage/localStorageDriver.ts","../src/storage/indexedDBDriver.ts","../src/storage/index.ts","../src/Logger.ts","../src/context/LoggerContext.tsx","../src/hooks/useLogger.ts","../src/components/FloatingButton.tsx","../src/components/LogItem.tsx","../src/components/LogList.tsx","../src/components/LogPanel.tsx","../src/components/LoggerViewer.tsx"],"names":["styleInject","css","insertAt","head","style","LocalStorageDriver","key","logs","e","data","DB_NAME","STORE_NAME","DB_VERSION","IndexedDBDriver","openDB","db","tx","store","log","getStorageDriver","type","Logger","dispatch","onLogAdded","level","message","extra","title","err","stack","initialState","loggerReducer","state","action","newLogs","LoggerContext","createContext","LoggerProvider","children","config","useReducer","isPanelOpen","setIsPanelOpen","React","storageRef","useRef","useEffect","loadedLogs","jsx","useLoggerContext","context","useContext","useLogger","debug","useCallback","error","object","clear","exportLogs","dataStr","downloadAnchorNode","FloatingButton","position","setPosition","useState","isDragging","dragOffset","handleMouseDown","rect","handleTouchStart","touch","handleMove","clientX","clientY","nextX","nextY","onMouseMove","onTouchMove","onEnd","handleResize","prev","handleClick","dynamicStyle","LogItem","isExpanded","setIsExpanded","formatTime","isoString","renderJson","getIcon","levelClass","jsxs","LogList","filter","search","filteredLogs","matchesFilter","matchesSearch","Virtuoso","_index","LogPanel","setFilter","setSearch","clearLogs","LoggerViewer","Fragment"],"mappings":"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","file":"index.mjs","sourcesContent":["\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\":root{--liql-primary: #6b21a8;--liql-primary-glow: rgba(107, 33, 168, .5);--liql-error: #ff4d4d;--liql-error-glow: rgba(255, 77, 77, .4);--liql-object: #00ff88;--liql-object-glow: rgba(0, 255, 136, .4);--liql-glass-bg: rgba(15, 23, 42, .9);--liql-glass-border: rgba(255, 255, 255, .1);--liql-glass-edge: rgba(255, 255, 255, .05);--liql-text-main: #f8fafc;--liql-text-muted: #94a3b8;--liql-font-family: \\\"Inter\\\", -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, sans-serif}.liql-floatingButton{position:fixed;right:20px;bottom:20px;width:50px;height:50px;border-radius:50%;background:radial-gradient(circle at 30% 30%,rgba(255,255,255,.15),transparent),linear-gradient(135deg,#6b21a8,#4c1d95);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);box-shadow:0 8px 32px #0006,0 0 15px var(--liql-primary-glow);display:flex;align-items:center;justify-content:center;cursor:grab;z-index:99999;border:1px solid var(--liql-glass-border);transition:all .4s cubic-bezier(.175,.885,.32,1.275);font-size:26px;color:#fff;user-select:none;touch-action:none}.liql-floatingButton:hover{transform:scale(1.1) rotate(5deg);box-shadow:0 12px 40px #00000080,0 0 25px var(--liql-primary-glow)}.liql-badge{position:absolute;top:-2px;right:-2px;background:var(--liql-error);color:#fff;border-radius:12px;min-width:20px;height:20px;padding:0 6px;font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;border:2px solid #0f172a;box-shadow:0 0 10px var(--liql-error-glow)}.liql-panel{position:fixed;background:var(--liql-glass-bg);backdrop-filter:blur(25px) saturate(180%);-webkit-backdrop-filter:blur(25px) saturate(180%);box-shadow:0 20px 50px #0009,inset 0 0 0 1px var(--liql-glass-edge);border:1px solid var(--liql-glass-border);border-radius:20px;display:flex;flex-direction:column;width:440px;height:680px;right:20px;bottom:20px;z-index:999999;overflow:hidden;font-family:var(--liql-font-family);color:var(--liql-text-main);animation:liql-slideUp .4s cubic-bezier(.23,1,.32,1)}.liql-panelHeader{background:#ffffff0d;padding:16px 20px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--liql-glass-border)}.liql-title{font-weight:700;letter-spacing:.5px;text-transform:uppercase;font-size:12px;color:var(--liql-text-muted)}.liql-controls{display:flex;gap:12px}.liql-btnAction{background:#ffffff14;border:1px solid var(--liql-glass-border);color:var(--liql-text-main);width:32px;height:32px;border-radius:8px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.liql-btnAction:hover{background:#ffffff26;transform:translateY(-2px)}.liql-filterBar{padding:12px 20px;display:flex;gap:10px;background:#0003;align-items:center}.liql-searchInput{flex:1;background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px 14px;color:#fff;font-size:13px}.liql-searchInput:focus{outline:none;border-color:var(--liql-primary);background:#ffffff14}.liql-selectFilter{background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px;color:#fff;font-size:12px;cursor:pointer}.liql-logListContainer{flex:1;padding:10px}.liql-logItem{margin-bottom:10px;padding:16px;border-radius:14px;background:#ffffff08;border:1px solid var(--liql-glass-border);transition:all .3s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden}.liql-logItem:hover{background:#ffffff0f;border-color:#fff3;transform:scale(1.01)}.liql-logItem-debug{border-left:4px solid var(--liql-primary)}.liql-logItem-error{border-left:4px solid var(--liql-error);box-shadow:inset 0 0 15px var(--liql-error-glow)}.liql-logItem-object{border-left:4px solid var(--liql-object);box-shadow:inset 0 0 15px var(--liql-object-glow)}.liql-logMeta{display:flex;justify-content:space-between;margin-bottom:8px;font-size:11px;font-weight:500;text-transform:uppercase}.liql-statusTag{padding:2px 8px;border-radius:6px;font-size:9px;font-weight:700}.liql-tag-debug{background:#3498db33;color:#3498db}.liql-tag-error{background:#ff4d4d33;color:#ff4d4d}.liql-tag-object{background:#0f83;color:#0f8}.liql-logTime{color:var(--liql-text-muted)}.liql-logContent{font-size:14px;line-height:1.5;color:#e2e8f0}.liql-expandedContent{margin-top:12px;padding:12px;background:#0000004d;border-radius:10px;font-family:JetBrains Mono,monospace;font-size:12px;border:1px solid var(--liql-glass-border);color:#a5f3fc;overflow-x:auto}.liql-footerActions{padding:14px 20px;background:#0003;display:flex;justify-content:space-between;align-items:center;border-top:1px solid var(--liql-glass-border)}.liql-storageInfo{font-size:10px;color:var(--liql-text-muted)}.liql-btnClose{background:linear-gradient(135deg,var(--liql-primary),#2980b9);border:none;padding:8px 16px;border-radius:8px;color:#fff;font-weight:600;font-size:13px;cursor:pointer;box-shadow:0 4px 12px var(--liql-primary-glow)}@keyframes liql-slideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}@media(max-width:600px){.liql-panel{width:100%!important;height:100%!important;bottom:0!important;right:0!important;left:0!important;border-radius:0;animation:none;background:#0f172a!important;backdrop-filter:none!important;-webkit-backdrop-filter:none!important}}\\n\")","import { LogEntry, StorageDriver } from '../types';\n\nexport class LocalStorageDriver implements StorageDriver {\n private key: string;\n\n constructor(key: string = 'ionic_react_logger_logs') {\n this.key = key;\n }\n\n async save(logs: LogEntry[]): Promise<void> {\n try {\n localStorage.setItem(this.key, JSON.stringify(logs));\n } catch (e) {\n console.error('Failed to save logs to localStorage', e);\n }\n }\n\n async load(): Promise<LogEntry[]> {\n try {\n const data = localStorage.getItem(this.key);\n return data ? JSON.parse(data) : [];\n } catch (e) {\n console.error('Failed to load logs from localStorage', e);\n return [];\n }\n }\n\n async clear(): Promise<void> {\n localStorage.removeItem(this.key);\n }\n}\n","import { openDB, IDBPDatabase } from 'idb';\nimport { LogEntry, StorageDriver } from '../types';\n\nconst DB_NAME = 'IonicReactLoggerDB';\nconst STORE_NAME = 'logs';\nconst DB_VERSION = 1;\n\nexport class IndexedDBDriver implements StorageDriver {\n private dbPromise: Promise<IDBPDatabase>;\n\n constructor() {\n this.dbPromise = openDB(DB_NAME, DB_VERSION, {\n upgrade(db) {\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME, { keyPath: 'id' });\n }\n },\n });\n }\n\n async save(logs: LogEntry[]): Promise<void> {\n const db = await this.dbPromise;\n const tx = db.transaction(STORE_NAME, 'readwrite');\n const store = tx.objectStore(STORE_NAME);\n\n // Clear existing logs first or manage them as needed\n // Simple implementation: clear and re-save everything to match the expected behavior of StorageDriver\n await store.clear();\n for (const log of logs) {\n await store.put(log);\n }\n await tx.done;\n }\n\n async load(): Promise<LogEntry[]> {\n const db = await this.dbPromise;\n return db.getAll(STORE_NAME);\n }\n\n async clear(): Promise<void> {\n const db = await this.dbPromise;\n const tx = db.transaction(STORE_NAME, 'readwrite');\n await tx.objectStore(STORE_NAME).clear();\n await tx.done;\n }\n}\n","import { StorageDriver, LogEntry } from '../types';\nimport { LocalStorageDriver } from './localStorageDriver';\nimport { IndexedDBDriver } from './indexedDBDriver';\n\nexport function getStorageDriver(type: 'localStorage' | 'indexedDB'): StorageDriver {\n if (type === 'indexedDB') {\n return new IndexedDBDriver();\n }\n return new LocalStorageDriver();\n}\n\nexport * from './localStorageDriver';\nexport * from './indexedDBDriver';\n","import { LogEntry, LogLevel } from './types';\n\ntype LoggerDispatch = (action: { type: 'ADD_LOG'; log: LogEntry } | { type: 'CLEAR_LOGS' }) => void;\n\n/**\n * Global Logger class to support logging from plain TypeScript classes\n * and handle early logs before the React Provider is mounted.\n */\nexport class Logger {\n private static dispatch: LoggerDispatch | null = null;\n private static logBuffer: LogEntry[] = [];\n private static onLogAddedCallback?: (log: LogEntry) => void;\n\n /**\n * Internal method to initialize the dispatcher from the React context.\n */\n static _setDispatcher(dispatch: LoggerDispatch, onLogAdded?: (log: LogEntry) => void) {\n this.dispatch = dispatch;\n this.onLogAddedCallback = onLogAdded;\n\n // Flush buffer\n if (this.logBuffer.length > 0) {\n this.logBuffer.forEach(log => {\n this.dispatch!({ type: 'ADD_LOG', log });\n this.onLogAddedCallback?.(log);\n });\n this.logBuffer = [];\n }\n }\n\n private static createLog(level: LogLevel, message: string, extra?: { title?: string, data?: any, stack?: string }): LogEntry {\n return {\n id: Math.random().toString(36).substring(2, 9),\n level,\n message,\n timestamp: new Date().toISOString(),\n ...extra\n };\n }\n\n private static addLog(log: LogEntry) {\n if (this.dispatch) {\n this.dispatch({ type: 'ADD_LOG', log });\n this.onLogAddedCallback?.(log);\n } else {\n this.logBuffer.push(log);\n }\n }\n\n /**\n * Log a debug message (Blue neon)\n */\n static debug(message: string, title?: string) {\n this.addLog(this.createLog('DEBUG', message, { title }));\n }\n\n /**\n * Log an error (Red neon). Supports Error objects for automatic stack trace capture.\n */\n static error(err: string | Error, title?: string) {\n const message = err instanceof Error ? err.message : err;\n const stack = err instanceof Error ? err.stack : undefined;\n this.addLog(this.createLog('ERROR', message, { title: title || 'Error', stack }));\n }\n\n /**\n * Log an object for visualization (Green neon).\n */\n static object(data: any, title?: string) {\n this.addLog(this.createLog('OBJECT', 'Object visualization', { title: title || 'Data Object', data }));\n }\n\n /**\n * Clear all logs.\n */\n static clear() {\n if (this.dispatch) {\n this.dispatch({ type: 'CLEAR_LOGS' });\n } else {\n this.logBuffer = [];\n }\n }\n}\n","import React, { createContext, useContext, useReducer, useEffect, useCallback, useRef } from 'react';\nimport { LogEntry, LogLevel, LoggerConfig, StorageDriver } from '../types';\nimport { getStorageDriver } from '../storage';\nimport { Logger } from '../Logger';\n\ninterface LoggerState {\n logs: LogEntry[];\n config: LoggerConfig;\n unreadCount: number;\n}\n\ntype LoggerAction =\n | { type: 'ADD_LOG'; log: LogEntry }\n | { type: 'SET_LOGS'; logs: LogEntry[] }\n | { type: 'CLEAR_LOGS' }\n | { type: 'SET_CONFIG'; config: Partial<LoggerConfig> }\n | { type: 'RESET_UNREAD' }\n | { type: 'INCREMENT_UNREAD' };\n\nconst initialState: LoggerState = {\n logs: [],\n config: {\n persistence: false,\n persistenceDriver: 'localStorage',\n maxLogs: 500,\n },\n unreadCount: 0,\n};\n\nfunction loggerReducer(state: LoggerState, action: LoggerAction): LoggerState {\n switch (action.type) {\n case 'ADD_LOG': {\n const newLogs = [action.log, ...state.logs].slice(0, state.config.maxLogs);\n return {\n ...state,\n logs: newLogs,\n };\n }\n case 'SET_LOGS':\n return { ...state, logs: [...state.logs, ...action.logs].slice(0, state.config.maxLogs) };\n case 'CLEAR_LOGS':\n return { ...state, logs: [], unreadCount: 0 };\n case 'SET_CONFIG':\n return { ...state, config: { ...state.config, ...action.config } };\n case 'RESET_UNREAD':\n return { ...state, unreadCount: 0 };\n case 'INCREMENT_UNREAD':\n return { ...state, unreadCount: state.unreadCount + 1 };\n default:\n return state;\n }\n}\n\ninterface LoggerContextType {\n state: LoggerState;\n dispatch: React.Dispatch<LoggerAction>;\n isPanelOpen: boolean;\n setIsPanelOpen: (open: boolean) => void;\n}\n\nconst LoggerContext = createContext<LoggerContextType | undefined>(undefined);\n\n/**\n * Provides the logging context to all child components.\n * This should wrap your entire application (e.g. in App.tsx).\n * \n * @param config Optional initial configuration for persistence and limits.\n */\nexport const LoggerProvider: React.FC<{ children: React.ReactNode; config?: LoggerConfig }> = ({\n children,\n config,\n}) => {\n const [state, dispatch] = useReducer(loggerReducer, {\n ...initialState,\n config: { ...initialState.config, ...config },\n });\n const [isPanelOpen, setIsPanelOpen] = React.useState(false);\n const storageRef = useRef<StorageDriver | null>(null);\n\n // Initialize storage driver and Logger singleton\n useEffect(() => {\n Logger._setDispatcher(dispatch, state.config.onLogAdded);\n\n if (state.config.persistence) {\n storageRef.current = getStorageDriver(state.config.persistenceDriver || 'localStorage');\n storageRef.current.load().then((loadedLogs) => {\n dispatch({ type: 'SET_LOGS', logs: loadedLogs });\n });\n }\n }, [state.config.persistence, state.config.persistenceDriver]);\n\n // Persist logs when they change\n useEffect(() => {\n if (state.config.persistence && storageRef.current) {\n storageRef.current.save(state.logs);\n }\n }, [state.logs, state.config.persistence]);\n\n return (\n <LoggerContext.Provider value={{ state, dispatch, isPanelOpen, setIsPanelOpen }}>\n {children}\n </LoggerContext.Provider>\n );\n};\n\n/**\n * Internal hook to access the logger context state.\n * Use the public `useLogger` hook for standard logging operations.\n */\nexport const useLoggerContext = () => {\n const context = useContext(LoggerContext);\n if (!context) {\n throw new Error('useLoggerContext must be used within a LoggerProvider');\n }\n return context;\n};\n","import { useCallback } from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\nimport { Logger } from '../Logger';\n\n/**\n * Main hook to interact with the Liquid Glass Logger.\n * \n * Provides methods for different logging levels and allows accessing\n * the current state of logs.\n * \n * @example\n * ```tsx\n * const { debug, error, object } = useLogger();\n * \n * debug('App started');\n * error(new Error('Failed to fetch'), 'API Error');\n * object({ user: 'John' }, 'Current User');\n * ```\n */\nexport const useLogger = () => {\n const { state } = useLoggerContext();\n\n /**\n * Log a debug message (Blue neon)\n */\n const debug = useCallback((message: string, title?: string) => {\n Logger.debug(message, title);\n }, []);\n\n /**\n * Log an error. If an Error object is passed, it automatically captures the stack trace.\n * (Red neon)\n */\n const error = useCallback((err: string | Error, title?: string) => {\n Logger.error(err, title);\n }, []);\n\n /**\n * Log a data object for inspection.\n * (Green neon)\n */\n const object = useCallback((data: any, title?: string) => {\n Logger.object(data, title);\n }, []);\n\n /**\n * Clears all logs from the current session and persistent storage.\n */\n const clear = useCallback(() => {\n Logger.clear();\n }, []);\n\n /**\n * Exports all logs as a JSON file download.\n */\n const exportLogs = useCallback(() => {\n const dataStr = \"data:text/json;charset=utf-8,\" + encodeURIComponent(JSON.stringify(state.logs, null, 2));\n const downloadAnchorNode = document.createElement('a');\n downloadAnchorNode.setAttribute(\"href\", dataStr);\n downloadAnchorNode.setAttribute(\"download\", `logs_${new Date().getTime()}.json`);\n document.body.appendChild(downloadAnchorNode);\n downloadAnchorNode.click();\n downloadAnchorNode.remove();\n }, [state.logs]);\n\n return {\n /** Register a debug message */\n debug,\n /** Register an error or exception */\n error,\n /** Register an object for JSON visualization */\n object,\n /** Clear all history */\n clear,\n /** Download history as JSON */\n exportLogs,\n /** List of all captured logs */\n logs: state.logs,\n /** Count of logs not yet viewed */\n unreadCount: state.unreadCount,\n };\n};\n","import React, { useState, useRef, useEffect, useCallback } from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\n\n/**\n * Draggable floating trigger button.\n * Uses hybrid positioning (CSS initial + JS drag) for maximum compatibility.\n */\nexport const FloatingButton: React.FC = () => {\n const { state, setIsPanelOpen } = useLoggerContext();\n\n // Default to null to use CSS positioning initially\n const [position, setPosition] = useState<{ x: number; y: number } | null>(null);\n const isDragging = useRef(false);\n const dragOffset = useRef({ x: 0, y: 0 });\n\n const handleMouseDown = (e: React.MouseEvent) => {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n isDragging.current = true;\n dragOffset.current = {\n x: e.clientX - rect.left,\n y: e.clientY - rect.top\n };\n };\n\n const handleTouchStart = (e: React.TouchEvent) => {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n isDragging.current = true;\n const touch = e.touches[0];\n dragOffset.current = {\n x: touch.clientX - rect.left,\n y: touch.clientY - rect.top\n };\n };\n\n const handleMove = useCallback((clientX: number, clientY: number) => {\n if (!isDragging.current) return;\n\n // Keep button within viewport\n const nextX = Math.max(10, Math.min(window.innerWidth - 60, clientX - dragOffset.current.x));\n const nextY = Math.max(10, Math.min(window.innerHeight - 60, clientY - dragOffset.current.y));\n\n setPosition({ x: nextX, y: nextY });\n }, []);\n\n useEffect(() => {\n const onMouseMove = (e: MouseEvent) => handleMove(e.clientX, e.clientY);\n const onTouchMove = (e: TouchEvent) => handleMove(e.touches[0].clientX, e.touches[0].clientY);\n const onEnd = () => {\n isDragging.current = false;\n };\n\n window.addEventListener('mousemove', onMouseMove);\n window.addEventListener('touchmove', onTouchMove, { passive: false });\n window.addEventListener('mouseup', onEnd);\n window.addEventListener('touchend', onEnd);\n\n return () => {\n window.removeEventListener('mousemove', onMouseMove);\n window.removeEventListener('touchmove', onTouchMove);\n window.removeEventListener('mouseup', onEnd);\n window.removeEventListener('touchend', onEnd);\n };\n }, [handleMove]);\n\n // Handle window resize to keep button in bounds\n useEffect(() => {\n const handleResize = () => {\n if (position) {\n setPosition(prev => {\n if (!prev) return null;\n return {\n x: Math.min(prev.x, window.innerWidth - 60),\n y: Math.min(prev.y, window.innerHeight - 60)\n };\n });\n }\n };\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, [position]);\n\n const handleClick = () => {\n if (isDragging.current) return;\n setIsPanelOpen(true);\n };\n\n // If never moved, let CSS handle it. If moved, use absolute pixel coordinates.\n const dynamicStyle: React.CSSProperties = position\n ? { left: `${position.x}px`, top: `${position.y}px`, right: 'auto', bottom: 'auto' }\n : {};\n\n return (\n <div\n className=\"liql-floatingButton\"\n style={dynamicStyle}\n onMouseDown={handleMouseDown}\n onTouchStart={handleTouchStart}\n onClick={handleClick}\n aria-label=\"Open Logger\"\n >\n {state.unreadCount > 0 && (\n <div className=\"liql-badge\">{state.unreadCount}</div>\n )}\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport { LogEntry } from '../types';\n\ninterface LogItemProps {\n log: LogEntry;\n}\n\nexport const LogItem: React.FC<LogItemProps> = ({ log }) => {\n const [isExpanded, setIsExpanded] = useState(false);\n\n const formatTime = (isoString: string) => {\n const date = new Date(isoString);\n return date.toTimeString().split(' ')[0];\n };\n\n const renderJson = (data: any) => {\n try {\n return (\n <pre className=\"liql-expandedContent\">\n {JSON.stringify(data, null, 2)}\n </pre>\n );\n } catch (e) {\n return <div>Error parsing object</div>;\n }\n };\n\n const getIcon = (level: string) => {\n switch (level) {\n case 'DEBUG': return '🐞';\n case 'ERROR': return '❌';\n case 'OBJECT': return '📦';\n default: return '📝';\n }\n };\n\n const levelClass = log.level.toLowerCase();\n\n return (\n <div\n className={`liql-logItem liql-logItem-${levelClass}`}\n onClick={() => setIsExpanded(!isExpanded)}\n >\n <div className=\"liql-logMeta\">\n <span className={`liql-statusTag liql-tag-${levelClass}`}>\n {getIcon(log.level)} {log.level}\n </span>\n <span className=\"liql-logTime\">{formatTime(log.timestamp)}</span>\n </div>\n <div className=\"liql-logContent\">\n {log.title && <strong style={{ color: 'var(--liql-primary)' }}>{log.title}: </strong>}\n {log.message}\n </div>\n\n {isExpanded && (\n <div className=\"liql-expandedContent\">\n {log.stack && (\n <div style={{ color: 'var(--liql-error)', marginBottom: '8px' }}>\n <strong>Stack Trace:</strong>\n <pre style={{ whiteSpace: 'pre-wrap', fontSize: '10px', marginTop: '4px' }}>{log.stack}</pre>\n </div>\n )}\n {log.data && (\n <div>\n <strong>Payload:</strong>\n {renderJson(log.data)}\n </div>\n )}\n {!log.data && !log.stack && <div>Full message: {log.message}</div>}\n </div>\n )}\n </div>\n );\n};\n","import React from 'react';\nimport { Virtuoso } from 'react-virtuoso';\nimport { LogItem } from './LogItem';\nimport { LogEntry } from '../types';\n\ninterface LogListProps {\n logs: LogEntry[];\n filter: string;\n search: string;\n}\n\nexport const LogList: React.FC<LogListProps> = ({ logs, filter, search }) => {\n const filteredLogs = React.useMemo(() => {\n return logs.filter(log => {\n const matchesFilter = filter === 'ALL' || log.level === filter;\n const matchesSearch = search === '' ||\n log.message.toLowerCase().includes(search.toLowerCase()) ||\n (log.title || '').toLowerCase().includes(search.toLowerCase());\n return matchesFilter && matchesSearch;\n }).reverse();\n }, [logs, filter, search]);\n\n return (\n <div className=\"liql-logListContainer\">\n <Virtuoso\n style={{ height: '100%' }}\n data={filteredLogs}\n itemContent={(_index: number, log: LogEntry) => <LogItem key={log.id} log={log} />}\n />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\nimport { LogList } from './LogList';\n\n/**\n * Main 'Liquid Glass' logging console.\n * Contains the log list, filtering, search, and action controls.\n */\nexport const LogPanel: React.FC = () => {\n const { state, setIsPanelOpen, dispatch } = useLoggerContext();\n const [filter, setFilter] = useState('ALL');\n const [search, setSearch] = useState('');\n\n const clearLogs = () => {\n if (confirm('Are you sure you want to clear all logs?')) {\n dispatch({ type: 'CLEAR_LOGS' });\n }\n };\n\n const exportLogs = () => {\n const dataStr = \"data:text/json;charset=utf-8,\" + encodeURIComponent(JSON.stringify(state.logs, null, 2));\n const downloadAnchorNode = document.createElement('a');\n downloadAnchorNode.setAttribute(\"href\", dataStr);\n downloadAnchorNode.setAttribute(\"download\", `logs_${new Date().getTime()}.json`);\n document.body.appendChild(downloadAnchorNode);\n downloadAnchorNode.click();\n downloadAnchorNode.remove();\n };\n\n if (!state) return null;\n\n return (\n <div className=\"liql-panel\">\n <div className=\"liql-panelHeader\">\n <div className=\"liql-titleGroup\">\n <span className=\"liql-title\">ReactLoggerApp console [{state.logs.length}]</span>\n </div>\n <div className=\"liql-controls\">\n <button className=\"liql-btnAction\" onClick={exportLogs} title=\"Export JSON\">📥</button>\n <button className=\"liql-btnAction\" onClick={clearLogs} title=\"Clear Logs\">🗑️</button>\n <button className=\"liql-btnAction\" onClick={() => setIsPanelOpen(false)} title=\"Minimize\">➖</button>\n </div>\n </div>\n\n <div className=\"liql-filterBar\">\n <input\n type=\"text\"\n placeholder=\"Search entries...\"\n className=\"liql-searchInput\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <select\n className=\"liql-selectFilter\"\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n >\n <option value=\"ALL\">ALL</option>\n <option value=\"DEBUG\">DEBUG</option>\n <option value=\"ERROR\">ERROR</option>\n <option value=\"OBJECT\">OBJECTS</option>\n </select>\n </div>\n\n <LogList logs={state.logs} filter={filter} search={search} />\n\n <div className=\"liql-footerActions\">\n <div className=\"liql-storageInfo\">\n {state.config.persistence ? `DRIVER: ${state.config.persistenceDriver?.toUpperCase()}` : 'SESSION MODE'}\n </div>\n <button className=\"liql-btnClose\" onClick={() => setIsPanelOpen(false)}>CLOSE CONSOLE</button>\n </div>\n </div>\n );\n};\n","import React from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\nimport { FloatingButton } from './FloatingButton';\nimport { LogPanel } from './LogPanel';\n\n/**\n * Main entry point for the Logger UI.\n * Renders the floating trigger button and conditionally shows the glass panel.\n * Should be placed at the root level of your application.\n */\nexport const LoggerViewer: React.FC = () => {\n const { isPanelOpen } = useLoggerContext();\n\n return (\n <>\n {!isPanelOpen && <FloatingButton />}\n {isPanelOpen && <LogPanel />}\n </>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/polyfills.ts","#style-inject:#style-inject","../src/styles/logger.css","../src/storage/localStorageDriver.ts","../src/storage/indexedDBDriver.ts","../src/storage/index.ts","../src/Logger.ts","../src/context/LoggerContext.tsx","../src/hooks/useLogger.ts","../src/components/FloatingButton.tsx","../src/components/LogItem.tsx","../src/components/LogList.tsx","../src/components/LogPanel.tsx","../src/components/LoggerViewer.tsx"],"names":["obj","prop","styleInject","css","insertAt","head","style","LocalStorageDriver","key","logs","e","data","DB_NAME","STORE_NAME","DB_VERSION","IndexedDBDriver","openDB","db","tx","store","log","getStorageDriver","type","Logger","dispatch","onLogAdded","level","message","extra","title","err","stack","initialState","loggerReducer","state","action","newLogs","LoggerContext","createContext","LoggerProvider","children","config","useReducer","isPanelOpen","setIsPanelOpen","React","storageRef","useRef","useEffect","loadedLogs","jsx","useLoggerContext","context","useContext","useLogger","debug","useCallback","error","object","clear","exportLogs","dataStr","downloadAnchorNode","FloatingButton","position","setPosition","useState","isDragging","dragOffset","handleMouseDown","rect","handleTouchStart","touch","handleMove","clientX","clientY","nextX","nextY","onMouseMove","onTouchMove","onEnd","handleResize","prev","handleClick","dynamicStyle","LogItem","isExpanded","setIsExpanded","formatTime","isoString","renderJson","getIcon","levelClass","jsxs","LogList","filter","search","filteredLogs","matchesFilter","matchesSearch","Virtuoso","_index","LogPanel","setFilter","setSearch","clearLogs","LoggerViewer","Fragment"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Polyfills for older browsers and Android WebView compatibility\n */\n\n// Polyfill for Object.hasOwn (ES2022)\n// Required for Android WebView < Chrome 93\nif (!Object.hasOwn) {\n Object.hasOwn = function (obj: object, prop: PropertyKey): boolean {\n return Object.prototype.hasOwnProperty.call(obj, prop);\n };\n}\n\nexport { };\n","\n export default function styleInject(css, { insertAt } = {}) {\n if (!css || typeof document === 'undefined') return\n \n const head = document.head || document.getElementsByTagName('head')[0]\n const style = document.createElement('style')\n style.type = 'text/css'\n \n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n \n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n }\n ","import styleInject from '#style-inject';styleInject(\":root{--liql-primary: #6b21a8;--liql-primary-glow: rgba(107, 33, 168, .5);--liql-error: #ff4d4d;--liql-error-glow: rgba(255, 77, 77, .4);--liql-object: #00ff88;--liql-object-glow: rgba(0, 255, 136, .4);--liql-glass-bg: rgba(15, 23, 42, .9);--liql-glass-border: rgba(255, 255, 255, .1);--liql-glass-edge: rgba(255, 255, 255, .05);--liql-text-main: #f8fafc;--liql-text-muted: #94a3b8;--liql-font-family: \\\"Inter\\\", -apple-system, BlinkMacSystemFont, \\\"Segoe UI\\\", Roboto, sans-serif}.liql-floatingButton{position:fixed;right:20px;bottom:20px;width:50px;height:50px;border-radius:50%;background:radial-gradient(circle at 30% 30%,rgba(255,255,255,.15),transparent),linear-gradient(135deg,#6b21a8,#4c1d95);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);box-shadow:0 8px 32px #0006,0 0 15px var(--liql-primary-glow);display:flex;align-items:center;justify-content:center;cursor:grab;z-index:99999;border:1px solid var(--liql-glass-border);transition:all .4s cubic-bezier(.175,.885,.32,1.275);font-size:26px;color:#fff;user-select:none;touch-action:none}.liql-floatingButton:hover{transform:scale(1.1) rotate(5deg);box-shadow:0 12px 40px #00000080,0 0 25px var(--liql-primary-glow)}.liql-badge{position:absolute;top:-2px;right:-2px;background:var(--liql-error);color:#fff;border-radius:12px;min-width:20px;height:20px;padding:0 6px;font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;border:2px solid #0f172a;box-shadow:0 0 10px var(--liql-error-glow)}.liql-panel{position:fixed;background:var(--liql-glass-bg);backdrop-filter:blur(25px) saturate(180%);-webkit-backdrop-filter:blur(25px) saturate(180%);box-shadow:0 20px 50px #0009,inset 0 0 0 1px var(--liql-glass-edge);border:1px solid var(--liql-glass-border);border-radius:20px;display:flex;flex-direction:column;width:440px;height:680px;right:20px;bottom:20px;z-index:999999;overflow:hidden;font-family:var(--liql-font-family);color:var(--liql-text-main);animation:liql-slideUp .4s cubic-bezier(.23,1,.32,1)}.liql-panelHeader{background:#ffffff0d;padding:16px 20px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--liql-glass-border)}.liql-title{font-weight:700;letter-spacing:.5px;text-transform:uppercase;font-size:12px;color:var(--liql-text-muted)}.liql-controls{display:flex;gap:12px}.liql-btnAction{background:#ffffff14;border:1px solid var(--liql-glass-border);color:var(--liql-text-main);width:32px;height:32px;border-radius:8px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.liql-btnAction:hover{background:#ffffff26;transform:translateY(-2px)}.liql-filterBar{padding:12px 20px;display:flex;gap:10px;background:#0003;align-items:center}.liql-searchInput{flex:1;background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px 14px;color:#fff;font-size:13px}.liql-searchInput:focus{outline:none;border-color:var(--liql-primary);background:#ffffff14}.liql-selectFilter{background:#ffffff0d;border:1px solid var(--liql-glass-border);border-radius:10px;padding:8px;color:#fff;font-size:12px;cursor:pointer}.liql-logListContainer{flex:1;padding:10px}.liql-logItem{margin-bottom:10px;padding:16px;border-radius:14px;background:#ffffff08;border:1px solid var(--liql-glass-border);transition:all .3s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden}.liql-logItem:hover{background:#ffffff0f;border-color:#fff3;transform:scale(1.01)}.liql-logItem-debug{border-left:4px solid var(--liql-primary)}.liql-logItem-error{border-left:4px solid var(--liql-error);box-shadow:inset 0 0 15px var(--liql-error-glow)}.liql-logItem-object{border-left:4px solid var(--liql-object);box-shadow:inset 0 0 15px var(--liql-object-glow)}.liql-logMeta{display:flex;justify-content:space-between;margin-bottom:8px;font-size:11px;font-weight:500;text-transform:uppercase}.liql-statusTag{padding:2px 8px;border-radius:6px;font-size:9px;font-weight:700}.liql-tag-debug{background:#3498db33;color:#3498db}.liql-tag-error{background:#ff4d4d33;color:#ff4d4d}.liql-tag-object{background:#0f83;color:#0f8}.liql-logTime{color:var(--liql-text-muted)}.liql-logContent{font-size:14px;line-height:1.5;color:#e2e8f0}.liql-expandedContent{margin-top:12px;padding:12px;background:#0000004d;border-radius:10px;font-family:JetBrains Mono,monospace;font-size:12px;border:1px solid var(--liql-glass-border);color:#a5f3fc;overflow-x:auto}.liql-footerActions{padding:14px 20px;background:#0003;display:flex;justify-content:space-between;align-items:center;border-top:1px solid var(--liql-glass-border)}.liql-storageInfo{font-size:10px;color:var(--liql-text-muted)}.liql-btnClose{background:linear-gradient(135deg,var(--liql-primary),#2980b9);border:none;padding:8px 16px;border-radius:8px;color:#fff;font-weight:600;font-size:13px;cursor:pointer;box-shadow:0 4px 12px var(--liql-primary-glow)}@keyframes liql-slideUp{0%{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}@media(max-width:600px){.liql-panel{width:100%!important;height:100%!important;bottom:0!important;right:0!important;left:0!important;border-radius:0;animation:none;background:#0f172a!important;backdrop-filter:none!important;-webkit-backdrop-filter:none!important}}\\n\")","import { LogEntry, StorageDriver } from '../types';\n\nexport class LocalStorageDriver implements StorageDriver {\n private key: string;\n\n constructor(key: string = 'ionic_react_logger_logs') {\n this.key = key;\n }\n\n async save(logs: LogEntry[]): Promise<void> {\n try {\n localStorage.setItem(this.key, JSON.stringify(logs));\n } catch (e) {\n console.error('Failed to save logs to localStorage', e);\n }\n }\n\n async load(): Promise<LogEntry[]> {\n try {\n const data = localStorage.getItem(this.key);\n return data ? JSON.parse(data) : [];\n } catch (e) {\n console.error('Failed to load logs from localStorage', e);\n return [];\n }\n }\n\n async clear(): Promise<void> {\n localStorage.removeItem(this.key);\n }\n}\n","import { openDB, IDBPDatabase } from 'idb';\nimport { LogEntry, StorageDriver } from '../types';\n\nconst DB_NAME = 'IonicReactLoggerDB';\nconst STORE_NAME = 'logs';\nconst DB_VERSION = 1;\n\nexport class IndexedDBDriver implements StorageDriver {\n private dbPromise: Promise<IDBPDatabase>;\n\n constructor() {\n this.dbPromise = openDB(DB_NAME, DB_VERSION, {\n upgrade(db) {\n if (!db.objectStoreNames.contains(STORE_NAME)) {\n db.createObjectStore(STORE_NAME, { keyPath: 'id' });\n }\n },\n });\n }\n\n async save(logs: LogEntry[]): Promise<void> {\n const db = await this.dbPromise;\n const tx = db.transaction(STORE_NAME, 'readwrite');\n const store = tx.objectStore(STORE_NAME);\n\n // Clear existing logs first or manage them as needed\n // Simple implementation: clear and re-save everything to match the expected behavior of StorageDriver\n await store.clear();\n for (const log of logs) {\n await store.put(log);\n }\n await tx.done;\n }\n\n async load(): Promise<LogEntry[]> {\n const db = await this.dbPromise;\n return db.getAll(STORE_NAME);\n }\n\n async clear(): Promise<void> {\n const db = await this.dbPromise;\n const tx = db.transaction(STORE_NAME, 'readwrite');\n await tx.objectStore(STORE_NAME).clear();\n await tx.done;\n }\n}\n","import { StorageDriver, LogEntry } from '../types';\nimport { LocalStorageDriver } from './localStorageDriver';\nimport { IndexedDBDriver } from './indexedDBDriver';\n\nexport function getStorageDriver(type: 'localStorage' | 'indexedDB'): StorageDriver {\n if (type === 'indexedDB') {\n return new IndexedDBDriver();\n }\n return new LocalStorageDriver();\n}\n\nexport * from './localStorageDriver';\nexport * from './indexedDBDriver';\n","import { LogEntry, LogLevel } from './types';\n\ntype LoggerDispatch = (action: { type: 'ADD_LOG'; log: LogEntry } | { type: 'CLEAR_LOGS' }) => void;\n\n/**\n * Global Logger class to support logging from plain TypeScript classes\n * and handle early logs before the React Provider is mounted.\n */\nexport class Logger {\n private static dispatch: LoggerDispatch | null = null;\n private static logBuffer: LogEntry[] = [];\n private static onLogAddedCallback?: (log: LogEntry) => void;\n\n /**\n * Internal method to initialize the dispatcher from the React context.\n */\n static _setDispatcher(dispatch: LoggerDispatch, onLogAdded?: (log: LogEntry) => void) {\n this.dispatch = dispatch;\n this.onLogAddedCallback = onLogAdded;\n\n // Flush buffer\n if (this.logBuffer.length > 0) {\n this.logBuffer.forEach(log => {\n this.dispatch!({ type: 'ADD_LOG', log });\n this.onLogAddedCallback?.(log);\n });\n this.logBuffer = [];\n }\n }\n\n private static createLog(level: LogLevel, message: string, extra?: { title?: string, data?: any, stack?: string }): LogEntry {\n return {\n id: Math.random().toString(36).substring(2, 9),\n level,\n message,\n timestamp: new Date().toISOString(),\n ...extra\n };\n }\n\n private static addLog(log: LogEntry) {\n if (this.dispatch) {\n this.dispatch({ type: 'ADD_LOG', log });\n this.onLogAddedCallback?.(log);\n } else {\n this.logBuffer.push(log);\n }\n }\n\n /**\n * Log a debug message (Blue neon)\n */\n static debug(message: string, title?: string) {\n this.addLog(this.createLog('DEBUG', message, { title }));\n }\n\n /**\n * Log an error (Red neon). Supports Error objects for automatic stack trace capture.\n */\n static error(err: string | Error, title?: string) {\n const message = err instanceof Error ? err.message : err;\n const stack = err instanceof Error ? err.stack : undefined;\n this.addLog(this.createLog('ERROR', message, { title: title || 'Error', stack }));\n }\n\n /**\n * Log an object for visualization (Green neon).\n */\n static object(data: any, title?: string) {\n this.addLog(this.createLog('OBJECT', 'Object visualization', { title: title || 'Data Object', data }));\n }\n\n /**\n * Clear all logs.\n */\n static clear() {\n if (this.dispatch) {\n this.dispatch({ type: 'CLEAR_LOGS' });\n } else {\n this.logBuffer = [];\n }\n }\n}\n","import React, { createContext, useContext, useReducer, useEffect, useCallback, useRef } from 'react';\nimport { LogEntry, LogLevel, LoggerConfig, StorageDriver } from '../types';\nimport { getStorageDriver } from '../storage';\nimport { Logger } from '../Logger';\n\ninterface LoggerState {\n logs: LogEntry[];\n config: LoggerConfig;\n unreadCount: number;\n}\n\ntype LoggerAction =\n | { type: 'ADD_LOG'; log: LogEntry }\n | { type: 'SET_LOGS'; logs: LogEntry[] }\n | { type: 'CLEAR_LOGS' }\n | { type: 'SET_CONFIG'; config: Partial<LoggerConfig> }\n | { type: 'RESET_UNREAD' }\n | { type: 'INCREMENT_UNREAD' };\n\nconst initialState: LoggerState = {\n logs: [],\n config: {\n persistence: false,\n persistenceDriver: 'localStorage',\n maxLogs: 500,\n },\n unreadCount: 0,\n};\n\nfunction loggerReducer(state: LoggerState, action: LoggerAction): LoggerState {\n switch (action.type) {\n case 'ADD_LOG': {\n const newLogs = [action.log, ...state.logs].slice(0, state.config.maxLogs);\n return {\n ...state,\n logs: newLogs,\n };\n }\n case 'SET_LOGS':\n return { ...state, logs: [...state.logs, ...action.logs].slice(0, state.config.maxLogs) };\n case 'CLEAR_LOGS':\n return { ...state, logs: [], unreadCount: 0 };\n case 'SET_CONFIG':\n return { ...state, config: { ...state.config, ...action.config } };\n case 'RESET_UNREAD':\n return { ...state, unreadCount: 0 };\n case 'INCREMENT_UNREAD':\n return { ...state, unreadCount: state.unreadCount + 1 };\n default:\n return state;\n }\n}\n\ninterface LoggerContextType {\n state: LoggerState;\n dispatch: React.Dispatch<LoggerAction>;\n isPanelOpen: boolean;\n setIsPanelOpen: (open: boolean) => void;\n}\n\nconst LoggerContext = createContext<LoggerContextType | undefined>(undefined);\n\n/**\n * Provides the logging context to all child components.\n * This should wrap your entire application (e.g. in App.tsx).\n * \n * @param config Optional initial configuration for persistence and limits.\n */\nexport const LoggerProvider: React.FC<{ children: React.ReactNode; config?: LoggerConfig }> = ({\n children,\n config,\n}) => {\n const [state, dispatch] = useReducer(loggerReducer, {\n ...initialState,\n config: { ...initialState.config, ...config },\n });\n const [isPanelOpen, setIsPanelOpen] = React.useState(false);\n const storageRef = useRef<StorageDriver | null>(null);\n\n // Initialize storage driver and Logger singleton\n useEffect(() => {\n Logger._setDispatcher(dispatch, state.config.onLogAdded);\n\n if (state.config.persistence) {\n storageRef.current = getStorageDriver(state.config.persistenceDriver || 'localStorage');\n storageRef.current.load().then((loadedLogs) => {\n dispatch({ type: 'SET_LOGS', logs: loadedLogs });\n });\n }\n }, [state.config.persistence, state.config.persistenceDriver]);\n\n // Persist logs when they change\n useEffect(() => {\n if (state.config.persistence && storageRef.current) {\n storageRef.current.save(state.logs);\n }\n }, [state.logs, state.config.persistence]);\n\n return (\n <LoggerContext.Provider value={{ state, dispatch, isPanelOpen, setIsPanelOpen }}>\n {children}\n </LoggerContext.Provider>\n );\n};\n\n/**\n * Internal hook to access the logger context state.\n * Use the public `useLogger` hook for standard logging operations.\n */\nexport const useLoggerContext = () => {\n const context = useContext(LoggerContext);\n if (!context) {\n throw new Error('useLoggerContext must be used within a LoggerProvider');\n }\n return context;\n};\n","import { useCallback } from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\nimport { Logger } from '../Logger';\n\n/**\n * Main hook to interact with the Liquid Glass Logger.\n * \n * Provides methods for different logging levels and allows accessing\n * the current state of logs.\n * \n * @example\n * ```tsx\n * const { debug, error, object } = useLogger();\n * \n * debug('App started');\n * error(new Error('Failed to fetch'), 'API Error');\n * object({ user: 'John' }, 'Current User');\n * ```\n */\nexport const useLogger = () => {\n const { state } = useLoggerContext();\n\n /**\n * Log a debug message (Blue neon)\n */\n const debug = useCallback((message: string, title?: string) => {\n Logger.debug(message, title);\n }, []);\n\n /**\n * Log an error. If an Error object is passed, it automatically captures the stack trace.\n * (Red neon)\n */\n const error = useCallback((err: string | Error, title?: string) => {\n Logger.error(err, title);\n }, []);\n\n /**\n * Log a data object for inspection.\n * (Green neon)\n */\n const object = useCallback((data: any, title?: string) => {\n Logger.object(data, title);\n }, []);\n\n /**\n * Clears all logs from the current session and persistent storage.\n */\n const clear = useCallback(() => {\n Logger.clear();\n }, []);\n\n /**\n * Exports all logs as a JSON file download.\n */\n const exportLogs = useCallback(() => {\n const dataStr = \"data:text/json;charset=utf-8,\" + encodeURIComponent(JSON.stringify(state.logs, null, 2));\n const downloadAnchorNode = document.createElement('a');\n downloadAnchorNode.setAttribute(\"href\", dataStr);\n downloadAnchorNode.setAttribute(\"download\", `logs_${new Date().getTime()}.json`);\n document.body.appendChild(downloadAnchorNode);\n downloadAnchorNode.click();\n downloadAnchorNode.remove();\n }, [state.logs]);\n\n return {\n /** Register a debug message */\n debug,\n /** Register an error or exception */\n error,\n /** Register an object for JSON visualization */\n object,\n /** Clear all history */\n clear,\n /** Download history as JSON */\n exportLogs,\n /** List of all captured logs */\n logs: state.logs,\n /** Count of logs not yet viewed */\n unreadCount: state.unreadCount,\n };\n};\n","import React, { useState, useRef, useEffect, useCallback } from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\n\n/**\n * Draggable floating trigger button.\n * Uses hybrid positioning (CSS initial + JS drag) for maximum compatibility.\n */\nexport const FloatingButton: React.FC = () => {\n const { state, setIsPanelOpen } = useLoggerContext();\n\n // Default to null to use CSS positioning initially\n const [position, setPosition] = useState<{ x: number; y: number } | null>(null);\n const isDragging = useRef(false);\n const dragOffset = useRef({ x: 0, y: 0 });\n\n const handleMouseDown = (e: React.MouseEvent) => {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n isDragging.current = true;\n dragOffset.current = {\n x: e.clientX - rect.left,\n y: e.clientY - rect.top\n };\n };\n\n const handleTouchStart = (e: React.TouchEvent) => {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n isDragging.current = true;\n const touch = e.touches[0];\n dragOffset.current = {\n x: touch.clientX - rect.left,\n y: touch.clientY - rect.top\n };\n };\n\n const handleMove = useCallback((clientX: number, clientY: number) => {\n if (!isDragging.current) return;\n\n // Keep button within viewport\n const nextX = Math.max(10, Math.min(window.innerWidth - 60, clientX - dragOffset.current.x));\n const nextY = Math.max(10, Math.min(window.innerHeight - 60, clientY - dragOffset.current.y));\n\n setPosition({ x: nextX, y: nextY });\n }, []);\n\n useEffect(() => {\n const onMouseMove = (e: MouseEvent) => handleMove(e.clientX, e.clientY);\n const onTouchMove = (e: TouchEvent) => handleMove(e.touches[0].clientX, e.touches[0].clientY);\n const onEnd = () => {\n isDragging.current = false;\n };\n\n window.addEventListener('mousemove', onMouseMove);\n window.addEventListener('touchmove', onTouchMove, { passive: false });\n window.addEventListener('mouseup', onEnd);\n window.addEventListener('touchend', onEnd);\n\n return () => {\n window.removeEventListener('mousemove', onMouseMove);\n window.removeEventListener('touchmove', onTouchMove);\n window.removeEventListener('mouseup', onEnd);\n window.removeEventListener('touchend', onEnd);\n };\n }, [handleMove]);\n\n // Handle window resize to keep button in bounds\n useEffect(() => {\n const handleResize = () => {\n if (position) {\n setPosition(prev => {\n if (!prev) return null;\n return {\n x: Math.min(prev.x, window.innerWidth - 60),\n y: Math.min(prev.y, window.innerHeight - 60)\n };\n });\n }\n };\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, [position]);\n\n const handleClick = () => {\n if (isDragging.current) return;\n setIsPanelOpen(true);\n };\n\n // If never moved, let CSS handle it. If moved, use absolute pixel coordinates.\n const dynamicStyle: React.CSSProperties = position\n ? { left: `${position.x}px`, top: `${position.y}px`, right: 'auto', bottom: 'auto' }\n : {};\n\n return (\n <div\n className=\"liql-floatingButton\"\n style={dynamicStyle}\n onMouseDown={handleMouseDown}\n onTouchStart={handleTouchStart}\n onClick={handleClick}\n aria-label=\"Open Logger\"\n >\n {state.unreadCount > 0 && (\n <div className=\"liql-badge\">{state.unreadCount}</div>\n )}\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport { LogEntry } from '../types';\n\ninterface LogItemProps {\n log: LogEntry;\n}\n\nexport const LogItem: React.FC<LogItemProps> = ({ log }) => {\n const [isExpanded, setIsExpanded] = useState(false);\n\n const formatTime = (isoString: string) => {\n const date = new Date(isoString);\n return date.toTimeString().split(' ')[0];\n };\n\n const renderJson = (data: any) => {\n try {\n return (\n <pre className=\"liql-expandedContent\">\n {JSON.stringify(data, null, 2)}\n </pre>\n );\n } catch (e) {\n return <div>Error parsing object</div>;\n }\n };\n\n const getIcon = (level: string) => {\n switch (level) {\n case 'DEBUG': return '🐞';\n case 'ERROR': return '❌';\n case 'OBJECT': return '📦';\n default: return '📝';\n }\n };\n\n const levelClass = log.level.toLowerCase();\n\n return (\n <div\n className={`liql-logItem liql-logItem-${levelClass}`}\n onClick={() => setIsExpanded(!isExpanded)}\n >\n <div className=\"liql-logMeta\">\n <span className={`liql-statusTag liql-tag-${levelClass}`}>\n {getIcon(log.level)} {log.level}\n </span>\n <span className=\"liql-logTime\">{formatTime(log.timestamp)}</span>\n </div>\n <div className=\"liql-logContent\">\n {log.title && <strong style={{ color: 'var(--liql-primary)' }}>{log.title}: </strong>}\n {log.message}\n </div>\n\n {isExpanded && (\n <div className=\"liql-expandedContent\">\n {log.stack && (\n <div style={{ color: 'var(--liql-error)', marginBottom: '8px' }}>\n <strong>Stack Trace:</strong>\n <pre style={{ whiteSpace: 'pre-wrap', fontSize: '10px', marginTop: '4px' }}>{log.stack}</pre>\n </div>\n )}\n {log.data && (\n <div>\n <strong>Payload:</strong>\n {renderJson(log.data)}\n </div>\n )}\n {!log.data && !log.stack && <div>Full message: {log.message}</div>}\n </div>\n )}\n </div>\n );\n};\n","import React from 'react';\nimport { Virtuoso } from 'react-virtuoso';\nimport { LogItem } from './LogItem';\nimport { LogEntry } from '../types';\n\ninterface LogListProps {\n logs: LogEntry[];\n filter: string;\n search: string;\n}\n\nexport const LogList: React.FC<LogListProps> = ({ logs, filter, search }) => {\n const filteredLogs = React.useMemo(() => {\n return logs.filter(log => {\n const matchesFilter = filter === 'ALL' || log.level === filter;\n const matchesSearch = search === '' ||\n log.message.toLowerCase().includes(search.toLowerCase()) ||\n (log.title || '').toLowerCase().includes(search.toLowerCase());\n return matchesFilter && matchesSearch;\n }).reverse();\n }, [logs, filter, search]);\n\n return (\n <div className=\"liql-logListContainer\">\n <Virtuoso\n style={{ height: '100%' }}\n data={filteredLogs}\n itemContent={(_index: number, log: LogEntry) => <LogItem key={log.id} log={log} />}\n />\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\nimport { LogList } from './LogList';\n\n/**\n * Main 'Liquid Glass' logging console.\n * Contains the log list, filtering, search, and action controls.\n */\nexport const LogPanel: React.FC = () => {\n const { state, setIsPanelOpen, dispatch } = useLoggerContext();\n const [filter, setFilter] = useState('ALL');\n const [search, setSearch] = useState('');\n\n const clearLogs = () => {\n if (confirm('Are you sure you want to clear all logs?')) {\n dispatch({ type: 'CLEAR_LOGS' });\n }\n };\n\n const exportLogs = () => {\n const dataStr = \"data:text/json;charset=utf-8,\" + encodeURIComponent(JSON.stringify(state.logs, null, 2));\n const downloadAnchorNode = document.createElement('a');\n downloadAnchorNode.setAttribute(\"href\", dataStr);\n downloadAnchorNode.setAttribute(\"download\", `logs_${new Date().getTime()}.json`);\n document.body.appendChild(downloadAnchorNode);\n downloadAnchorNode.click();\n downloadAnchorNode.remove();\n };\n\n if (!state) return null;\n\n return (\n <div className=\"liql-panel\">\n <div className=\"liql-panelHeader\">\n <div className=\"liql-titleGroup\">\n <span className=\"liql-title\">ReactLoggerApp console [{state.logs.length}]</span>\n </div>\n <div className=\"liql-controls\">\n <button className=\"liql-btnAction\" onClick={exportLogs} title=\"Export JSON\">📥</button>\n <button className=\"liql-btnAction\" onClick={clearLogs} title=\"Clear Logs\">🗑️</button>\n <button className=\"liql-btnAction\" onClick={() => setIsPanelOpen(false)} title=\"Minimize\">➖</button>\n </div>\n </div>\n\n <div className=\"liql-filterBar\">\n <input\n type=\"text\"\n placeholder=\"Search entries...\"\n className=\"liql-searchInput\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <select\n className=\"liql-selectFilter\"\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n >\n <option value=\"ALL\">ALL</option>\n <option value=\"DEBUG\">DEBUG</option>\n <option value=\"ERROR\">ERROR</option>\n <option value=\"OBJECT\">OBJECTS</option>\n </select>\n </div>\n\n <LogList logs={state.logs} filter={filter} search={search} />\n\n <div className=\"liql-footerActions\">\n <div className=\"liql-storageInfo\">\n {state.config.persistence ? `DRIVER: ${state.config.persistenceDriver?.toUpperCase()}` : 'SESSION MODE'}\n </div>\n <button className=\"liql-btnClose\" onClick={() => setIsPanelOpen(false)}>CLOSE CONSOLE</button>\n </div>\n </div>\n );\n};\n","import React from 'react';\nimport { useLoggerContext } from '../context/LoggerContext';\nimport { FloatingButton } from './FloatingButton';\nimport { LogPanel } from './LogPanel';\n\n/**\n * Main entry point for the Logger UI.\n * Renders the floating trigger button and conditionally shows the glass panel.\n * Should be placed at the root level of your application.\n */\nexport const LoggerViewer: React.FC = () => {\n const { isPanelOpen } = useLoggerContext();\n\n return (\n <>\n {!isPanelOpen && <FloatingButton />}\n {isPanelOpen && <LogPanel />}\n </>\n );\n};\n"]}
|