@trustquery/browser 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -73,7 +73,19 @@ ui: {
73
73
  ```javascript
74
74
  events: {
75
75
  onWordHover: (matchData) => { /* ... */ },
76
- onWordClick: (matchData) => { /* ... */ }
76
+ onWordClick: (matchData) => { /* ... */ },
77
+ onValidationChange: (validationState) => {
78
+ // Fires when validation state changes
79
+ // validationState: {
80
+ // hasBlockingError: boolean,
81
+ // errors: Array, // matches with message-state: 'error'
82
+ // warnings: Array, // matches with message-state: 'warning'
83
+ // info: Array // matches with message-state: 'info'
84
+ // }
85
+
86
+ // Example: Disable submit button on blocking errors
87
+ submitButton.disabled = validationState.hasBlockingError;
88
+ }
77
89
  }
78
90
  ```
79
91
 
@@ -12,10 +12,13 @@ class OverlayRenderer {
12
12
  this.options = {
13
13
  theme: options.theme || 'light',
14
14
  commandHandlers: options.commandHandlers || null,
15
+ debug: options.debug || false,
15
16
  ...options
16
17
  };
17
18
 
18
- console.log('[OverlayRenderer] Initialized');
19
+ if (this.options.debug) {
20
+ console.log('[OverlayRenderer] Initialized');
21
+ }
19
22
  }
20
23
 
21
24
  /**
@@ -35,7 +38,9 @@ class OverlayRenderer {
35
38
  // Update overlay
36
39
  this.overlay.innerHTML = linesHTML;
37
40
 
38
- console.log('[OverlayRenderer] Rendered', lines.length, 'lines with', matches.length, 'matches');
41
+ if (this.options.debug) {
42
+ console.log('[OverlayRenderer] Rendered', lines.length, 'lines with', matches.length, 'matches');
43
+ }
39
44
  }
40
45
 
41
46
  /**
@@ -345,8 +350,6 @@ class CommandScanner {
345
350
  // Sort by length (longest first) to match longer patterns first
346
351
  commands.sort((a, b) => b.match.length - a.match.length);
347
352
 
348
- console.log('[CommandScanner] Parsed commands:', commands.length, commands);
349
-
350
353
  return commands;
351
354
  }
352
355
 
@@ -369,7 +372,11 @@ class CommandScanner {
369
372
  matches.push(...lineMatches);
370
373
  });
371
374
 
372
- console.log('[CommandScanner] Found', matches.length, 'matches');
375
+ // Only log when matches are found
376
+ if (matches.length > 0) {
377
+ console.log(`[CommandScanner] Found ${matches.length} matches`);
378
+ }
379
+
373
380
  return matches;
374
381
  }
375
382
 
@@ -769,7 +776,9 @@ class DropdownManager {
769
776
  this.selectedDropdownIndex = 0;
770
777
  this.keyboardHandler = null;
771
778
 
772
- console.log('[DropdownManager] Initialized with offset:', this.options.dropdownOffset);
779
+ if (this.options.debug) {
780
+ console.log('[DropdownManager] Initialized with offset:', this.options.dropdownOffset);
781
+ }
773
782
  }
774
783
 
775
784
  /**
@@ -850,7 +859,9 @@ class DropdownManager {
850
859
  document.addEventListener('click', this.closeDropdownHandler);
851
860
  }, 0);
852
861
 
853
- console.log('[DropdownManager] Dropdown shown with', options.length, 'options');
862
+ if (this.options.debug) {
863
+ console.log('[DropdownManager] Dropdown shown with', options.length, 'options');
864
+ }
854
865
  }
855
866
 
856
867
  /**
@@ -1284,7 +1295,9 @@ class DropdownManager {
1284
1295
  * @param {Object} matchData - Match data
1285
1296
  */
1286
1297
  handleDropdownSelect(option, matchData) {
1287
- console.log('[DropdownManager] Dropdown option selected:', option, 'for:', matchData.text);
1298
+ if (this.options.debug) {
1299
+ console.log('[DropdownManager] Dropdown option selected:', option, 'for:', matchData.text);
1300
+ }
1288
1301
 
1289
1302
  // Check if option has on-select.display
1290
1303
  if (option['on-select'] && option['on-select'].display && this.options.textarea) {
@@ -1310,7 +1323,9 @@ class DropdownManager {
1310
1323
  const inputEvent = new Event('input', { bubbles: true });
1311
1324
  textarea.dispatchEvent(inputEvent);
1312
1325
 
1313
- console.log('[DropdownManager] Appended to', matchData.text, '→', newText);
1326
+ if (this.options.debug) {
1327
+ console.log('[DropdownManager] Appended to', matchData.text, '→', newText);
1328
+ }
1314
1329
  }
1315
1330
  }
1316
1331
 
@@ -1335,7 +1350,9 @@ class DropdownManager {
1335
1350
  */
1336
1351
  destroy() {
1337
1352
  this.cleanup();
1338
- console.log('[DropdownManager] Destroyed');
1353
+ if (this.options.debug) {
1354
+ console.log('[DropdownManager] Destroyed');
1355
+ }
1339
1356
  }
1340
1357
  }
1341
1358
 
@@ -1367,17 +1384,21 @@ class InteractionHandler {
1367
1384
  this.bubbleManager = new BubbleManager({
1368
1385
  bubbleDelay: this.options.bubbleDelay,
1369
1386
  styleManager: this.options.styleManager,
1370
- commandHandlers: this.options.commandHandlers
1387
+ commandHandlers: this.options.commandHandlers,
1388
+ debug: this.options.debug
1371
1389
  });
1372
1390
 
1373
1391
  this.dropdownManager = new DropdownManager({
1374
1392
  styleManager: this.options.styleManager,
1375
1393
  textarea: this.options.textarea,
1376
1394
  onWordClick: this.options.onWordClick,
1377
- dropdownOffset: this.options.dropdownOffset
1395
+ dropdownOffset: this.options.dropdownOffset,
1396
+ debug: this.options.debug
1378
1397
  });
1379
1398
 
1380
- console.log('[InteractionHandler] Initialized');
1399
+ if (this.options.debug) {
1400
+ console.log('[InteractionHandler] Initialized');
1401
+ }
1381
1402
  }
1382
1403
 
1383
1404
  /**
@@ -1415,7 +1436,9 @@ class InteractionHandler {
1415
1436
  }
1416
1437
  });
1417
1438
 
1418
- console.log('[InteractionHandler] Updated with', matches.length, 'interactive elements');
1439
+ if (this.options.debug) {
1440
+ console.log('[InteractionHandler] Updated with', matches.length, 'interactive elements');
1441
+ }
1419
1442
  }
1420
1443
 
1421
1444
  /**
@@ -2503,6 +2526,112 @@ class AutoGrow {
2503
2526
  }
2504
2527
  }
2505
2528
 
2529
+ // ValidationStateManager - Tracks validation state and triggers callbacks
2530
+
2531
+ class ValidationStateManager {
2532
+ /**
2533
+ * Create validation state manager
2534
+ * @param {Object} options - Configuration
2535
+ */
2536
+ constructor(options = {}) {
2537
+ this.options = {
2538
+ onValidationChange: options.onValidationChange || null,
2539
+ ...options
2540
+ };
2541
+
2542
+ this.state = {
2543
+ hasBlockingError: false,
2544
+ errors: [], // matches with message-state: 'error'
2545
+ warnings: [], // matches with message-state: 'warning'
2546
+ info: [] // matches with message-state: 'info'
2547
+ };
2548
+
2549
+ console.log('[ValidationStateManager] Initialized');
2550
+ }
2551
+
2552
+ /**
2553
+ * Update validation state based on current matches
2554
+ * @param {Array} matches - Current matches from scanner
2555
+ */
2556
+ update(matches) {
2557
+ // Reset state
2558
+ const newState = {
2559
+ hasBlockingError: false,
2560
+ errors: [],
2561
+ warnings: [],
2562
+ info: []
2563
+ };
2564
+
2565
+ // Categorize current matches
2566
+ matches.forEach(match => {
2567
+ const messageState = match.intent?.handler?.['message-state'];
2568
+ const blockSubmit = match.intent?.handler?.['block-submit'] === true;
2569
+
2570
+ if (blockSubmit) {
2571
+ newState.hasBlockingError = true;
2572
+ }
2573
+
2574
+ switch (messageState) {
2575
+ case 'error':
2576
+ newState.errors.push(match);
2577
+ break;
2578
+ case 'warning':
2579
+ newState.warnings.push(match);
2580
+ break;
2581
+ case 'info':
2582
+ newState.info.push(match);
2583
+ break;
2584
+ }
2585
+ });
2586
+
2587
+ // Check if state changed
2588
+ const stateChanged =
2589
+ this.state.hasBlockingError !== newState.hasBlockingError ||
2590
+ this.state.errors.length !== newState.errors.length ||
2591
+ this.state.warnings.length !== newState.warnings.length ||
2592
+ this.state.info.length !== newState.info.length;
2593
+
2594
+ if (stateChanged) {
2595
+ this.state = newState;
2596
+
2597
+ // Trigger callback
2598
+ if (this.options.onValidationChange) {
2599
+ this.options.onValidationChange(this.state);
2600
+ }
2601
+
2602
+ console.log('[ValidationStateManager] State changed:', {
2603
+ hasBlockingError: newState.hasBlockingError,
2604
+ errors: newState.errors.length,
2605
+ warnings: newState.warnings.length,
2606
+ info: newState.info.length
2607
+ });
2608
+ }
2609
+ }
2610
+
2611
+ /**
2612
+ * Get current validation state
2613
+ * @returns {Object} Current validation state
2614
+ */
2615
+ getState() {
2616
+ return { ...this.state };
2617
+ }
2618
+
2619
+ /**
2620
+ * Reset validation state to empty
2621
+ */
2622
+ reset() {
2623
+ this.update([]);
2624
+ }
2625
+
2626
+ /**
2627
+ * Check if there are blocking errors
2628
+ * @returns {boolean} True if there are blocking errors
2629
+ */
2630
+ hasBlockingErrors() {
2631
+ return this.state.hasBlockingError;
2632
+ }
2633
+ }
2634
+
2506
2635
  // TrustQuery - Lightweight library to make textareas interactive
2507
2636
  // Turns matching words into interactive elements with hover bubbles and click actions
2508
2637
 
@@ -2607,6 +2736,7 @@ class TrustQuery {
2607
2736
  // Events (callbacks)
2608
2737
  onWordClick: events.onWordClick || options.onWordClick || null,
2609
2738
  onWordHover: events.onWordHover || options.onWordHover || null,
2739
+ onValidationChange: events.onValidationChange || options.onValidationChange || null,
2610
2740
 
2611
2741
  // Theme/style options (passed to StyleManager)
2612
2742
  backgroundColor: ui.backgroundColor || options.backgroundColor,
@@ -2643,7 +2773,8 @@ class TrustQuery {
2643
2773
  // Initialize renderer
2644
2774
  this.renderer = new OverlayRenderer(this.overlay, {
2645
2775
  theme: this.options.theme,
2646
- commandHandlers: this.commandHandlers // Pass handlers for styling
2776
+ commandHandlers: this.commandHandlers, // Pass handlers for styling
2777
+ debug: this.options.debug // Pass debug flag
2647
2778
  });
2648
2779
 
2649
2780
  // Initialize scanner (will be configured when command map loads)
@@ -2657,7 +2788,13 @@ class TrustQuery {
2657
2788
  onWordHover: this.options.onWordHover,
2658
2789
  styleManager: this.styleManager, // Pass style manager for bubbles/dropdowns
2659
2790
  commandHandlers: this.commandHandlers, // Pass handlers for bubble content
2660
- textarea: this.textarea // Pass textarea for on-select display updates
2791
+ textarea: this.textarea, // Pass textarea for on-select display updates
2792
+ debug: this.options.debug // Pass debug flag
2793
+ });
2794
+
2795
+ // Initialize validation state manager
2796
+ this.validationStateManager = new ValidationStateManager({
2797
+ onValidationChange: this.options.onValidationChange
2661
2798
  });
2662
2799
 
2663
2800
  // Initialize features
@@ -2856,6 +2993,11 @@ class TrustQuery {
2856
2993
 
2857
2994
  // Update interaction handler with new elements
2858
2995
  this.interactionHandler.update();
2996
+
2997
+ // Update validation state
2998
+ if (this.validationStateManager) {
2999
+ this.validationStateManager.update(matches);
3000
+ }
2859
3001
  }
2860
3002
 
2861
3003
  /**