juxscript 1.0.86 → 1.0.88

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/lib/componentsv2/base/BaseEngine.d.ts +102 -0
  2. package/lib/componentsv2/base/BaseEngine.d.ts.map +1 -0
  3. package/lib/componentsv2/base/BaseSkin.d.ts +54 -0
  4. package/lib/componentsv2/base/BaseSkin.d.ts.map +1 -0
  5. package/lib/componentsv2/base/GlobalBus.d.ts +22 -0
  6. package/lib/componentsv2/base/GlobalBus.d.ts.map +1 -0
  7. package/lib/componentsv2/base/State.d.ts +18 -0
  8. package/lib/componentsv2/base/State.d.ts.map +1 -0
  9. package/lib/componentsv2/element/component.d.ts +7 -0
  10. package/lib/componentsv2/element/component.d.ts.map +1 -0
  11. package/lib/componentsv2/element/engine.d.ts +43 -0
  12. package/lib/componentsv2/element/engine.d.ts.map +1 -0
  13. package/lib/componentsv2/element/skin.d.ts +10 -0
  14. package/lib/componentsv2/element/skin.d.ts.map +1 -0
  15. package/lib/componentsv2/grid/component.d.ts +14 -0
  16. package/lib/componentsv2/grid/component.d.ts.map +1 -0
  17. package/lib/componentsv2/grid/engine.d.ts +40 -0
  18. package/lib/componentsv2/grid/engine.d.ts.map +1 -0
  19. package/lib/componentsv2/grid/skin.d.ts +11 -0
  20. package/lib/componentsv2/grid/skin.d.ts.map +1 -0
  21. package/lib/componentsv2/index.d.ts +41 -0
  22. package/lib/componentsv2/index.d.ts.map +1 -0
  23. package/lib/componentsv2/index.js +5 -1
  24. package/lib/componentsv2/index.js.map +1 -1
  25. package/lib/componentsv2/index.ts +6 -1
  26. package/lib/componentsv2/input/component.d.ts +6 -0
  27. package/lib/componentsv2/input/component.d.ts.map +1 -0
  28. package/lib/componentsv2/input/engine.d.ts +27 -0
  29. package/lib/componentsv2/input/engine.d.ts.map +1 -0
  30. package/lib/componentsv2/input/skin.d.ts +11 -0
  31. package/lib/componentsv2/input/skin.d.ts.map +1 -0
  32. package/lib/componentsv2/juxerror/component.d.ts +28 -0
  33. package/lib/componentsv2/juxerror/component.d.ts.map +1 -0
  34. package/lib/componentsv2/juxerror/component.js +101 -0
  35. package/lib/componentsv2/juxerror/component.js.map +1 -0
  36. package/lib/componentsv2/juxerror/component.ts +125 -0
  37. package/lib/componentsv2/juxerror/engine.d.ts +35 -0
  38. package/lib/componentsv2/juxerror/engine.d.ts.map +1 -0
  39. package/lib/componentsv2/juxerror/engine.js +190 -0
  40. package/lib/componentsv2/juxerror/engine.js.map +1 -0
  41. package/lib/componentsv2/juxerror/engine.ts +241 -0
  42. package/lib/componentsv2/juxerror/skin.d.ts +11 -0
  43. package/lib/componentsv2/juxerror/skin.d.ts.map +1 -0
  44. package/lib/componentsv2/juxerror/skin.js +180 -0
  45. package/lib/componentsv2/juxerror/skin.js.map +1 -0
  46. package/lib/componentsv2/juxerror/skin.ts +200 -0
  47. package/lib/componentsv2/juxerror/structure.css +351 -0
  48. package/lib/componentsv2/list/component.d.ts +27 -0
  49. package/lib/componentsv2/list/component.d.ts.map +1 -0
  50. package/lib/componentsv2/list/engine.d.ts +69 -0
  51. package/lib/componentsv2/list/engine.d.ts.map +1 -0
  52. package/lib/componentsv2/list/skin.d.ts +20 -0
  53. package/lib/componentsv2/list/skin.d.ts.map +1 -0
  54. package/lib/componentsv2/plugins/ClientSQLitePlugin.d.ts +21 -0
  55. package/lib/componentsv2/plugins/ClientSQLitePlugin.d.ts.map +1 -0
  56. package/lib/componentsv2/plugins/IndexedDBPlugin.d.ts +18 -0
  57. package/lib/componentsv2/plugins/IndexedDBPlugin.d.ts.map +1 -0
  58. package/lib/componentsv2/plugins/LocalStoragePlugin.d.ts +20 -0
  59. package/lib/componentsv2/plugins/LocalStoragePlugin.d.ts.map +1 -0
  60. package/lib/componentsv2/plugins/ServerSQLitePlugin.d.ts +25 -0
  61. package/lib/componentsv2/plugins/ServerSQLitePlugin.d.ts.map +1 -0
  62. package/lib/componentsv2/stubs/ComponentSkin.ts.stub +2 -1
  63. package/lib/globals.d.ts +5 -21
  64. package/lib/utils/fetch.d.ts +176 -0
  65. package/lib/utils/fetch.d.ts.map +1 -0
  66. package/package.json +2 -4
  67. package/types/css.d.ts +0 -4
  68. package/types/globals.d.ts +0 -16
@@ -0,0 +1,241 @@
1
+ import { BaseEngine, BaseState } from '../base/BaseEngine.js';
2
+ import { GlobalBus } from '../base/GlobalBus.js';
3
+
4
+ export interface StackFrame {
5
+ file: string;
6
+ line: number;
7
+ column: number;
8
+ function: string;
9
+ code?: string;
10
+ isUserCode: boolean;
11
+ }
12
+
13
+ export interface JuxErrorState extends BaseState {
14
+ title: string;
15
+ message: string;
16
+ stack: StackFrame[];
17
+ rawStack: string;
18
+ timestamp: number;
19
+ errorType: 'runtime' | 'compile' | 'network' | 'validation' | 'unknown';
20
+ culpritFrame: StackFrame | null;
21
+ expanded: boolean;
22
+ }
23
+
24
+ export interface JuxErrorOptions {
25
+ autoShow?: boolean;
26
+ }
27
+
28
+ export class JuxErrorEngine extends BaseEngine<JuxErrorState, JuxErrorOptions> {
29
+ constructor(id: string = 'jux-error', options: JuxErrorOptions = {}) {
30
+ super(id, options);
31
+ }
32
+
33
+ protected prepareState(id: string, options: JuxErrorOptions): JuxErrorState {
34
+ return {
35
+ // BaseState requirements
36
+ id,
37
+ classes: ['jux-error'],
38
+ visible: false,
39
+ disabled: false,
40
+ loading: false,
41
+ attributes: {},
42
+ // JuxErrorState specifics
43
+ title: '',
44
+ message: '',
45
+ stack: [],
46
+ rawStack: '',
47
+ timestamp: 0,
48
+ errorType: 'unknown',
49
+ culpritFrame: null,
50
+ expanded: false
51
+ };
52
+ }
53
+
54
+ // --- Public API ---
55
+
56
+ show(error: Error | string, type: JuxErrorState['errorType'] = 'runtime'): this {
57
+ const err = typeof error === 'string' ? new Error(error) : error;
58
+ const stack = this.#parseStack(err.stack || '');
59
+ const culprit = this.#findCulprit(stack);
60
+
61
+ this.updateState({
62
+ visible: true,
63
+ title: err.name || 'Error',
64
+ message: err.message,
65
+ stack,
66
+ rawStack: err.stack || '',
67
+ timestamp: Date.now(),
68
+ errorType: type,
69
+ culpritFrame: culprit,
70
+ expanded: false
71
+ });
72
+
73
+ this.emit('error:show', { type, message: err.message });
74
+ return this;
75
+ }
76
+
77
+ showCompileError(file: string, line: number, message: string, code?: string): this {
78
+ const culprit: StackFrame = {
79
+ file,
80
+ line,
81
+ column: 0,
82
+ function: '<compile>',
83
+ code,
84
+ isUserCode: true
85
+ };
86
+
87
+ this.updateState({
88
+ visible: true,
89
+ title: 'Compile Error',
90
+ message,
91
+ stack: [culprit],
92
+ rawStack: '',
93
+ timestamp: Date.now(),
94
+ errorType: 'compile',
95
+ culpritFrame: culprit,
96
+ expanded: false
97
+ });
98
+
99
+ this.emit('error:compile', { file, line, message });
100
+ return this;
101
+ }
102
+
103
+ showNetworkError(url: string, status: number, message: string): this {
104
+ this.updateState({
105
+ visible: true,
106
+ title: `Network Error (${status})`,
107
+ message: `${message}\n\nURL: ${url}`,
108
+ stack: [],
109
+ rawStack: '',
110
+ timestamp: Date.now(),
111
+ errorType: 'network',
112
+ culpritFrame: null,
113
+ expanded: false
114
+ });
115
+
116
+ this.emit('error:network', { url, status, message });
117
+ return this;
118
+ }
119
+
120
+ showValidationError(field: string, message: string): this {
121
+ this.updateState({
122
+ visible: true,
123
+ title: 'Validation Error',
124
+ message: `${field}: ${message}`,
125
+ stack: [],
126
+ rawStack: '',
127
+ timestamp: Date.now(),
128
+ errorType: 'validation',
129
+ culpritFrame: null,
130
+ expanded: false
131
+ });
132
+
133
+ this.emit('error:validation', { field, message });
134
+ return this;
135
+ }
136
+
137
+ dismiss(): this {
138
+ this.updateState({ visible: false });
139
+ this.emit('error:dismiss', {});
140
+ return this;
141
+ }
142
+
143
+ toggleExpanded(): this {
144
+ this.updateState({ expanded: !this.state.expanded });
145
+ this.emit('error:toggle', { expanded: this.state.expanded });
146
+ return this;
147
+ }
148
+
149
+ // --- Stack Parsing ---
150
+
151
+ #parseStack(rawStack: string): StackFrame[] {
152
+ const lines = rawStack.split('\n').slice(1);
153
+ const frames: StackFrame[] = [];
154
+
155
+ for (const line of lines) {
156
+ const frame = this.#parseStackLine(line.trim());
157
+ if (frame) frames.push(frame);
158
+ }
159
+
160
+ return frames;
161
+ }
162
+
163
+ #parseStackLine(line: string): StackFrame | null {
164
+ // Chrome/V8: "at functionName (file:line:column)" or "at file:line:column"
165
+ const chromeMatch = line.match(/^at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?$/);
166
+ if (chromeMatch) {
167
+ const [, func, file, lineNum, col] = chromeMatch;
168
+ return {
169
+ function: func || '<anonymous>',
170
+ file: this.#cleanFilePath(file),
171
+ line: parseInt(lineNum, 10),
172
+ column: parseInt(col, 10),
173
+ isUserCode: this.#isUserCode(file)
174
+ };
175
+ }
176
+
177
+ // Firefox: "functionName@file:line:column"
178
+ const firefoxMatch = line.match(/^(.*)@(.+?):(\d+):(\d+)$/);
179
+ if (firefoxMatch) {
180
+ const [, func, file, lineNum, col] = firefoxMatch;
181
+ return {
182
+ function: func || '<anonymous>',
183
+ file: this.#cleanFilePath(file),
184
+ line: parseInt(lineNum, 10),
185
+ column: parseInt(col, 10),
186
+ isUserCode: this.#isUserCode(file)
187
+ };
188
+ }
189
+
190
+ return null;
191
+ }
192
+
193
+ #cleanFilePath(file: string): string {
194
+ return file
195
+ .replace(/^https?:\/\/[^/]+/, '')
196
+ .replace(/\?.*$/, '');
197
+ }
198
+
199
+ #isUserCode(file: string): boolean {
200
+ const nonUserPatterns = [
201
+ /node_modules/,
202
+ /^\[native code\]/,
203
+ /<anonymous>/,
204
+ /^internal\//,
205
+ /^node:/,
206
+ /extensions\//,
207
+ /juxscript\/lib\/componentsv2/
208
+ ];
209
+ return !nonUserPatterns.some(p => p.test(file));
210
+ }
211
+
212
+ #findCulprit(stack: StackFrame[]): StackFrame | null {
213
+ return stack.find(frame => frame.isUserCode) || stack[0] || null;
214
+ }
215
+
216
+ // --- Global Error Handler ---
217
+
218
+ static installGlobalHandler(engine: JuxErrorEngine): () => void {
219
+ const errorHandler = (event: ErrorEvent) => {
220
+ engine.show(event.error || event.message, 'runtime');
221
+ event.preventDefault();
222
+ };
223
+
224
+ const rejectionHandler = (event: PromiseRejectionEvent) => {
225
+ const error = event.reason instanceof Error
226
+ ? event.reason
227
+ : new Error(String(event.reason));
228
+ engine.show(error, 'runtime');
229
+ event.preventDefault();
230
+ };
231
+
232
+ window.addEventListener('error', errorHandler);
233
+ window.addEventListener('unhandledrejection', rejectionHandler);
234
+
235
+ // Return cleanup function
236
+ return () => {
237
+ window.removeEventListener('error', errorHandler);
238
+ window.removeEventListener('unhandledrejection', rejectionHandler);
239
+ };
240
+ }
241
+ }
@@ -0,0 +1,11 @@
1
+ import { BaseSkin } from '../base/BaseSkin.js';
2
+ import { JuxErrorEngine, JuxErrorState } from './engine.js';
3
+ export declare class JuxErrorSkin extends BaseSkin<JuxErrorState, JuxErrorEngine> {
4
+ #private;
5
+ constructor(engine: JuxErrorEngine);
6
+ protected get structureCss(): string;
7
+ protected createRoot(): HTMLElement;
8
+ protected updateSkin(state: JuxErrorState): void;
9
+ protected bindEvents(root: HTMLElement): void;
10
+ }
11
+ //# sourceMappingURL=skin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skin.d.ts","sourceRoot":"","sources":["skin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAc,MAAM,aAAa,CAAC;AAGxE,qBAAa,YAAa,SAAQ,QAAQ,CAAC,aAAa,EAAE,cAAc,CAAC;;gBAIzD,MAAM,EAAE,cAAc;IAIlC,SAAS,KAAK,YAAY,IAAI,MAAM,CAEnC;IAED,SAAS,CAAC,UAAU,IAAI,WAAW;IAanC,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAyIhD,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;CAiChD"}
@@ -0,0 +1,180 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _JuxErrorSkin_instances, _JuxErrorSkin_overlay, _JuxErrorSkin_keydownHandler, _JuxErrorSkin_renderError, _JuxErrorSkin_renderCulprit, _JuxErrorSkin_renderStackSection, _JuxErrorSkin_renderFrame, _JuxErrorSkin_getTypeIcon, _JuxErrorSkin_formatTime, _JuxErrorSkin_escapeHtml, _JuxErrorSkin_copyErrorDetails;
13
+ import { BaseSkin } from '../base/BaseSkin.js';
14
+ import structureCss from './structure.css';
15
+ export class JuxErrorSkin extends BaseSkin {
16
+ constructor(engine) {
17
+ super(engine);
18
+ _JuxErrorSkin_instances.add(this);
19
+ _JuxErrorSkin_overlay.set(this, null);
20
+ _JuxErrorSkin_keydownHandler.set(this, null);
21
+ }
22
+ get structureCss() {
23
+ return structureCss;
24
+ }
25
+ createRoot() {
26
+ const root = document.createElement('div');
27
+ root.className = 'jux-error-root';
28
+ __classPrivateFieldSet(this, _JuxErrorSkin_overlay, document.createElement('div'), "f");
29
+ __classPrivateFieldGet(this, _JuxErrorSkin_overlay, "f").className = 'jux-error-overlay';
30
+ __classPrivateFieldGet(this, _JuxErrorSkin_overlay, "f").setAttribute('aria-live', 'assertive');
31
+ __classPrivateFieldGet(this, _JuxErrorSkin_overlay, "f").setAttribute('role', 'alert');
32
+ root.appendChild(__classPrivateFieldGet(this, _JuxErrorSkin_overlay, "f"));
33
+ return root;
34
+ }
35
+ updateSkin(state) {
36
+ if (!__classPrivateFieldGet(this, _JuxErrorSkin_overlay, "f") || !this.root)
37
+ return;
38
+ // Apply base attributes
39
+ this.applySkinAttributes(this.root, state);
40
+ if (!state.visible) {
41
+ __classPrivateFieldGet(this, _JuxErrorSkin_overlay, "f").classList.remove('jux-error-visible');
42
+ __classPrivateFieldGet(this, _JuxErrorSkin_overlay, "f").innerHTML = '';
43
+ return;
44
+ }
45
+ __classPrivateFieldGet(this, _JuxErrorSkin_overlay, "f").classList.add('jux-error-visible');
46
+ __classPrivateFieldGet(this, _JuxErrorSkin_overlay, "f").innerHTML = __classPrivateFieldGet(this, _JuxErrorSkin_instances, "m", _JuxErrorSkin_renderError).call(this, state);
47
+ }
48
+ bindEvents(root) {
49
+ root.addEventListener('click', (e) => {
50
+ const target = e.target;
51
+ // Close button or backdrop
52
+ if (target.closest('.jux-error-close') ||
53
+ target.closest('.jux-error-dismiss') ||
54
+ target.closest('.jux-error-backdrop')) {
55
+ this.engine.dismiss();
56
+ return;
57
+ }
58
+ // Toggle stack trace
59
+ if (target.closest('.jux-error-stack-toggle')) {
60
+ this.engine.toggleExpanded();
61
+ return;
62
+ }
63
+ // Copy button
64
+ if (target.closest('.jux-error-copy')) {
65
+ __classPrivateFieldGet(this, _JuxErrorSkin_instances, "m", _JuxErrorSkin_copyErrorDetails).call(this);
66
+ return;
67
+ }
68
+ });
69
+ // ESC key to dismiss
70
+ __classPrivateFieldSet(this, _JuxErrorSkin_keydownHandler, (e) => {
71
+ if (e.key === 'Escape' && this.engine.state.visible) {
72
+ this.engine.dismiss();
73
+ }
74
+ }, "f");
75
+ document.addEventListener('keydown', __classPrivateFieldGet(this, _JuxErrorSkin_keydownHandler, "f"));
76
+ }
77
+ }
78
+ _JuxErrorSkin_overlay = new WeakMap(), _JuxErrorSkin_keydownHandler = new WeakMap(), _JuxErrorSkin_instances = new WeakSet(), _JuxErrorSkin_renderError = function _JuxErrorSkin_renderError(state) {
79
+ const typeIcon = __classPrivateFieldGet(this, _JuxErrorSkin_instances, "m", _JuxErrorSkin_getTypeIcon).call(this, state.errorType);
80
+ const typeClass = `jux-error-type-${state.errorType}`;
81
+ return `
82
+ <div class="jux-error-backdrop"></div>
83
+ <div class="jux-error-dialog ${typeClass}">
84
+ <header class="jux-error-header">
85
+ <span class="jux-error-icon">${typeIcon}</span>
86
+ <h2 class="jux-error-title">${__classPrivateFieldGet(this, _JuxErrorSkin_instances, "m", _JuxErrorSkin_escapeHtml).call(this, state.title)}</h2>
87
+ <button class="jux-error-close" aria-label="Dismiss error">×</button>
88
+ </header>
89
+
90
+ <div class="jux-error-body">
91
+ <p class="jux-error-message">${__classPrivateFieldGet(this, _JuxErrorSkin_instances, "m", _JuxErrorSkin_escapeHtml).call(this, state.message)}</p>
92
+
93
+ ${state.culpritFrame ? __classPrivateFieldGet(this, _JuxErrorSkin_instances, "m", _JuxErrorSkin_renderCulprit).call(this, state.culpritFrame) : ''}
94
+
95
+ ${state.stack.length > 0 ? __classPrivateFieldGet(this, _JuxErrorSkin_instances, "m", _JuxErrorSkin_renderStackSection).call(this, state) : ''}
96
+ </div>
97
+
98
+ <footer class="jux-error-footer">
99
+ <span class="jux-error-timestamp">${__classPrivateFieldGet(this, _JuxErrorSkin_instances, "m", _JuxErrorSkin_formatTime).call(this, state.timestamp)}</span>
100
+ <div class="jux-error-actions">
101
+ <button class="jux-error-copy" title="Copy error details">📋 Copy</button>
102
+ <button class="jux-error-dismiss">Dismiss</button>
103
+ </div>
104
+ </footer>
105
+ </div>
106
+ `;
107
+ }, _JuxErrorSkin_renderCulprit = function _JuxErrorSkin_renderCulprit(frame) {
108
+ return `
109
+ <div class="jux-error-culprit">
110
+ <div class="jux-error-culprit-header">
111
+ <span class="jux-error-culprit-icon">👉</span>
112
+ <span class="jux-error-culprit-file">${__classPrivateFieldGet(this, _JuxErrorSkin_instances, "m", _JuxErrorSkin_escapeHtml).call(this, frame.file)}</span>
113
+ <span class="jux-error-culprit-location">:${frame.line}:${frame.column}</span>
114
+ </div>
115
+ ${frame.code ? `
116
+ <pre class="jux-error-culprit-code"><code>${__classPrivateFieldGet(this, _JuxErrorSkin_instances, "m", _JuxErrorSkin_escapeHtml).call(this, frame.code)}</code></pre>
117
+ ` : ''}
118
+ <div class="jux-error-culprit-function">
119
+ in <code>${__classPrivateFieldGet(this, _JuxErrorSkin_instances, "m", _JuxErrorSkin_escapeHtml).call(this, frame.function)}</code>
120
+ </div>
121
+ </div>
122
+ `;
123
+ }, _JuxErrorSkin_renderStackSection = function _JuxErrorSkin_renderStackSection(state) {
124
+ const expandedClass = state.expanded ? 'jux-error-stack-expanded' : '';
125
+ return `
126
+ <div class="jux-error-stack-section ${expandedClass}">
127
+ <button class="jux-error-stack-toggle">
128
+ <span class="jux-error-stack-toggle-icon">${state.expanded ? '▼' : '▶'}</span>
129
+ Stack Trace (${state.stack.length} frames)
130
+ </button>
131
+ <div class="jux-error-stack-frames">
132
+ ${state.stack.map((frame, i) => __classPrivateFieldGet(this, _JuxErrorSkin_instances, "m", _JuxErrorSkin_renderFrame).call(this, frame, i)).join('')}
133
+ </div>
134
+ </div>
135
+ `;
136
+ }, _JuxErrorSkin_renderFrame = function _JuxErrorSkin_renderFrame(frame, index) {
137
+ const userClass = frame.isUserCode ? 'jux-error-frame-user' : 'jux-error-frame-lib';
138
+ return `
139
+ <div class="jux-error-frame ${userClass}" data-index="${index}">
140
+ <span class="jux-error-frame-index">${index}</span>
141
+ <span class="jux-error-frame-function">${__classPrivateFieldGet(this, _JuxErrorSkin_instances, "m", _JuxErrorSkin_escapeHtml).call(this, frame.function)}</span>
142
+ <span class="jux-error-frame-location">
143
+ ${__classPrivateFieldGet(this, _JuxErrorSkin_instances, "m", _JuxErrorSkin_escapeHtml).call(this, frame.file)}:${frame.line}:${frame.column}
144
+ </span>
145
+ </div>
146
+ `;
147
+ }, _JuxErrorSkin_getTypeIcon = function _JuxErrorSkin_getTypeIcon(type) {
148
+ const icons = {
149
+ runtime: '💥',
150
+ compile: '🔨',
151
+ network: '🌐',
152
+ validation: '⚠️',
153
+ unknown: '❓'
154
+ };
155
+ return icons[type];
156
+ }, _JuxErrorSkin_formatTime = function _JuxErrorSkin_formatTime(timestamp) {
157
+ return new Date(timestamp).toLocaleTimeString();
158
+ }, _JuxErrorSkin_escapeHtml = function _JuxErrorSkin_escapeHtml(str) {
159
+ const div = document.createElement('div');
160
+ div.textContent = str;
161
+ return div.innerHTML;
162
+ }, _JuxErrorSkin_copyErrorDetails = function _JuxErrorSkin_copyErrorDetails() {
163
+ const state = this.engine.state;
164
+ const details = [
165
+ `${state.title}: ${state.message}`,
166
+ '',
167
+ state.culpritFrame ? `File: ${state.culpritFrame.file}:${state.culpritFrame.line}` : '',
168
+ '',
169
+ 'Stack Trace:',
170
+ ...state.stack.map(f => ` at ${f.function} (${f.file}:${f.line}:${f.column})`)
171
+ ].filter(Boolean).join('\n');
172
+ navigator.clipboard.writeText(details).then(() => {
173
+ const copyBtn = __classPrivateFieldGet(this, _JuxErrorSkin_overlay, "f")?.querySelector('.jux-error-copy');
174
+ if (copyBtn) {
175
+ copyBtn.textContent = '✓ Copied!';
176
+ setTimeout(() => { copyBtn.textContent = '📋 Copy'; }, 1500);
177
+ }
178
+ });
179
+ };
180
+ //# sourceMappingURL=skin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skin.js","sourceRoot":"","sources":["skin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,200 @@
1
+ import { BaseSkin } from '../base/BaseSkin.js';
2
+ import { JuxErrorEngine, JuxErrorState, StackFrame } from './engine.js';
3
+ import structureCss from './structure.css';
4
+
5
+ export class JuxErrorSkin extends BaseSkin<JuxErrorState, JuxErrorEngine> {
6
+ #overlay: HTMLElement | null = null;
7
+ #keydownHandler: ((e: KeyboardEvent) => void) | null = null;
8
+
9
+ constructor(engine: JuxErrorEngine) {
10
+ super(engine);
11
+ }
12
+
13
+ protected get structureCss(): string {
14
+ return structureCss;
15
+ }
16
+
17
+ protected createRoot(): HTMLElement {
18
+ const root = document.createElement('div');
19
+ root.className = 'jux-error-root';
20
+
21
+ this.#overlay = document.createElement('div');
22
+ this.#overlay.className = 'jux-error-overlay';
23
+ this.#overlay.setAttribute('aria-live', 'assertive');
24
+ this.#overlay.setAttribute('role', 'alert');
25
+ root.appendChild(this.#overlay);
26
+
27
+ return root;
28
+ }
29
+
30
+ protected updateSkin(state: JuxErrorState): void {
31
+ if (!this.#overlay || !this.root) return;
32
+
33
+ // Apply base attributes
34
+ this.applySkinAttributes(this.root, state);
35
+
36
+ if (!state.visible) {
37
+ this.#overlay.classList.remove('jux-error-visible');
38
+ this.#overlay.innerHTML = '';
39
+ return;
40
+ }
41
+
42
+ this.#overlay.classList.add('jux-error-visible');
43
+ this.#overlay.innerHTML = this.#renderError(state);
44
+ }
45
+
46
+ #renderError(state: JuxErrorState): string {
47
+ const typeIcon = this.#getTypeIcon(state.errorType);
48
+ const typeClass = `jux-error-type-${state.errorType}`;
49
+
50
+ return `
51
+ <div class="jux-error-backdrop"></div>
52
+ <div class="jux-error-dialog ${typeClass}">
53
+ <header class="jux-error-header">
54
+ <span class="jux-error-icon">${typeIcon}</span>
55
+ <h2 class="jux-error-title">${this.#escapeHtml(state.title)}</h2>
56
+ <button class="jux-error-close" aria-label="Dismiss error">×</button>
57
+ </header>
58
+
59
+ <div class="jux-error-body">
60
+ <p class="jux-error-message">${this.#escapeHtml(state.message)}</p>
61
+
62
+ ${state.culpritFrame ? this.#renderCulprit(state.culpritFrame) : ''}
63
+
64
+ ${state.stack.length > 0 ? this.#renderStackSection(state) : ''}
65
+ </div>
66
+
67
+ <footer class="jux-error-footer">
68
+ <span class="jux-error-timestamp">${this.#formatTime(state.timestamp)}</span>
69
+ <div class="jux-error-actions">
70
+ <button class="jux-error-copy" title="Copy error details">📋 Copy</button>
71
+ <button class="jux-error-dismiss">Dismiss</button>
72
+ </div>
73
+ </footer>
74
+ </div>
75
+ `;
76
+ }
77
+
78
+ #renderCulprit(frame: StackFrame): string {
79
+ return `
80
+ <div class="jux-error-culprit">
81
+ <div class="jux-error-culprit-header">
82
+ <span class="jux-error-culprit-icon">👉</span>
83
+ <span class="jux-error-culprit-file">${this.#escapeHtml(frame.file)}</span>
84
+ <span class="jux-error-culprit-location">:${frame.line}:${frame.column}</span>
85
+ </div>
86
+ ${frame.code ? `
87
+ <pre class="jux-error-culprit-code"><code>${this.#escapeHtml(frame.code)}</code></pre>
88
+ ` : ''}
89
+ <div class="jux-error-culprit-function">
90
+ in <code>${this.#escapeHtml(frame.function)}</code>
91
+ </div>
92
+ </div>
93
+ `;
94
+ }
95
+
96
+ #renderStackSection(state: JuxErrorState): string {
97
+ const expandedClass = state.expanded ? 'jux-error-stack-expanded' : '';
98
+
99
+ return `
100
+ <div class="jux-error-stack-section ${expandedClass}">
101
+ <button class="jux-error-stack-toggle">
102
+ <span class="jux-error-stack-toggle-icon">${state.expanded ? '▼' : '▶'}</span>
103
+ Stack Trace (${state.stack.length} frames)
104
+ </button>
105
+ <div class="jux-error-stack-frames">
106
+ ${state.stack.map((frame, i) => this.#renderFrame(frame, i)).join('')}
107
+ </div>
108
+ </div>
109
+ `;
110
+ }
111
+
112
+ #renderFrame(frame: StackFrame, index: number): string {
113
+ const userClass = frame.isUserCode ? 'jux-error-frame-user' : 'jux-error-frame-lib';
114
+
115
+ return `
116
+ <div class="jux-error-frame ${userClass}" data-index="${index}">
117
+ <span class="jux-error-frame-index">${index}</span>
118
+ <span class="jux-error-frame-function">${this.#escapeHtml(frame.function)}</span>
119
+ <span class="jux-error-frame-location">
120
+ ${this.#escapeHtml(frame.file)}:${frame.line}:${frame.column}
121
+ </span>
122
+ </div>
123
+ `;
124
+ }
125
+
126
+ #getTypeIcon(type: JuxErrorState['errorType']): string {
127
+ const icons: Record<JuxErrorState['errorType'], string> = {
128
+ runtime: '💥',
129
+ compile: '🔨',
130
+ network: '🌐',
131
+ validation: '⚠️',
132
+ unknown: '❓'
133
+ };
134
+ return icons[type];
135
+ }
136
+
137
+ #formatTime(timestamp: number): string {
138
+ return new Date(timestamp).toLocaleTimeString();
139
+ }
140
+
141
+ #escapeHtml(str: string): string {
142
+ const div = document.createElement('div');
143
+ div.textContent = str;
144
+ return div.innerHTML;
145
+ }
146
+
147
+ #copyErrorDetails(): void {
148
+ const state = this.engine.state;
149
+ const details = [
150
+ `${state.title}: ${state.message}`,
151
+ '',
152
+ state.culpritFrame ? `File: ${state.culpritFrame.file}:${state.culpritFrame.line}` : '',
153
+ '',
154
+ 'Stack Trace:',
155
+ ...state.stack.map(f => ` at ${f.function} (${f.file}:${f.line}:${f.column})`)
156
+ ].filter(Boolean).join('\n');
157
+
158
+ navigator.clipboard.writeText(details).then(() => {
159
+ const copyBtn = this.#overlay?.querySelector('.jux-error-copy');
160
+ if (copyBtn) {
161
+ copyBtn.textContent = '✓ Copied!';
162
+ setTimeout(() => { copyBtn.textContent = '📋 Copy'; }, 1500);
163
+ }
164
+ });
165
+ }
166
+
167
+ protected bindEvents(root: HTMLElement): void {
168
+ root.addEventListener('click', (e: MouseEvent) => {
169
+ const target = e.target as HTMLElement;
170
+
171
+ // Close button or backdrop
172
+ if (target.closest('.jux-error-close') ||
173
+ target.closest('.jux-error-dismiss') ||
174
+ target.closest('.jux-error-backdrop')) {
175
+ this.engine.dismiss();
176
+ return;
177
+ }
178
+
179
+ // Toggle stack trace
180
+ if (target.closest('.jux-error-stack-toggle')) {
181
+ this.engine.toggleExpanded();
182
+ return;
183
+ }
184
+
185
+ // Copy button
186
+ if (target.closest('.jux-error-copy')) {
187
+ this.#copyErrorDetails();
188
+ return;
189
+ }
190
+ });
191
+
192
+ // ESC key to dismiss
193
+ this.#keydownHandler = (e: KeyboardEvent) => {
194
+ if (e.key === 'Escape' && this.engine.state.visible) {
195
+ this.engine.dismiss();
196
+ }
197
+ };
198
+ document.addEventListener('keydown', this.#keydownHandler);
199
+ }
200
+ }