zero-query 0.9.9 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +33 -32
  2. package/cli/args.js +1 -1
  3. package/cli/commands/build.js +2 -2
  4. package/cli/commands/bundle.js +15 -15
  5. package/cli/commands/create.js +2 -2
  6. package/cli/commands/dev/devtools/index.js +1 -1
  7. package/cli/commands/dev/devtools/js/core.js +14 -14
  8. package/cli/commands/dev/devtools/js/elements.js +4 -4
  9. package/cli/commands/dev/devtools/js/stats.js +1 -1
  10. package/cli/commands/dev/devtools/styles.css +2 -2
  11. package/cli/commands/dev/index.js +2 -2
  12. package/cli/commands/dev/logger.js +1 -1
  13. package/cli/commands/dev/overlay.js +21 -14
  14. package/cli/commands/dev/server.js +5 -5
  15. package/cli/commands/dev/validator.js +7 -7
  16. package/cli/commands/dev/watcher.js +6 -6
  17. package/cli/help.js +3 -3
  18. package/cli/index.js +2 -2
  19. package/cli/scaffold/default/app/app.js +17 -18
  20. package/cli/scaffold/default/app/components/about.js +9 -9
  21. package/cli/scaffold/default/app/components/api-demo.js +6 -6
  22. package/cli/scaffold/default/app/components/contact-card.js +4 -4
  23. package/cli/scaffold/default/app/components/contacts/contacts.css +2 -2
  24. package/cli/scaffold/default/app/components/contacts/contacts.html +3 -3
  25. package/cli/scaffold/default/app/components/contacts/contacts.js +11 -11
  26. package/cli/scaffold/default/app/components/counter.js +8 -8
  27. package/cli/scaffold/default/app/components/home.js +13 -13
  28. package/cli/scaffold/default/app/components/not-found.js +1 -1
  29. package/cli/scaffold/default/app/components/playground/playground.css +1 -1
  30. package/cli/scaffold/default/app/components/playground/playground.html +11 -11
  31. package/cli/scaffold/default/app/components/playground/playground.js +11 -11
  32. package/cli/scaffold/default/app/components/todos.js +8 -8
  33. package/cli/scaffold/default/app/components/toolkit/toolkit.css +1 -1
  34. package/cli/scaffold/default/app/components/toolkit/toolkit.html +4 -4
  35. package/cli/scaffold/default/app/components/toolkit/toolkit.js +7 -7
  36. package/cli/scaffold/default/app/routes.js +1 -1
  37. package/cli/scaffold/default/app/store.js +1 -1
  38. package/cli/scaffold/default/global.css +2 -2
  39. package/cli/scaffold/default/index.html +2 -2
  40. package/cli/scaffold/minimal/app/app.js +6 -7
  41. package/cli/scaffold/minimal/app/components/about.js +5 -5
  42. package/cli/scaffold/minimal/app/components/counter.js +6 -6
  43. package/cli/scaffold/minimal/app/components/home.js +8 -8
  44. package/cli/scaffold/minimal/app/components/not-found.js +1 -1
  45. package/cli/scaffold/minimal/app/routes.js +1 -1
  46. package/cli/scaffold/minimal/app/store.js +1 -1
  47. package/cli/scaffold/minimal/global.css +2 -2
  48. package/cli/scaffold/minimal/index.html +1 -1
  49. package/cli/scaffold/ssr/app/app.js +1 -2
  50. package/cli/scaffold/ssr/app/components/about.js +5 -5
  51. package/cli/scaffold/ssr/app/components/home.js +2 -2
  52. package/cli/scaffold/ssr/app/components/not-found.js +1 -1
  53. package/cli/scaffold/ssr/app/routes.js +1 -1
  54. package/cli/scaffold/ssr/global.css +2 -2
  55. package/cli/scaffold/ssr/index.html +2 -2
  56. package/cli/scaffold/ssr/server/index.js +4 -4
  57. package/cli/utils.js +6 -6
  58. package/dist/zquery.dist.zip +0 -0
  59. package/dist/zquery.js +508 -227
  60. package/dist/zquery.min.js +2 -2
  61. package/index.d.ts +16 -13
  62. package/index.js +7 -5
  63. package/package.json +2 -2
  64. package/src/component.js +64 -63
  65. package/src/core.js +15 -15
  66. package/src/diff.js +38 -38
  67. package/src/errors.js +17 -17
  68. package/src/expression.js +15 -17
  69. package/src/http.js +4 -4
  70. package/src/reactive.js +75 -9
  71. package/src/router.js +104 -24
  72. package/src/ssr.js +28 -28
  73. package/src/store.js +103 -21
  74. package/src/utils.js +64 -12
  75. package/tests/audit.test.js +143 -15
  76. package/tests/cli.test.js +20 -20
  77. package/tests/component.test.js +121 -121
  78. package/tests/core.test.js +56 -56
  79. package/tests/diff.test.js +42 -42
  80. package/tests/errors.test.js +5 -5
  81. package/tests/expression.test.js +58 -53
  82. package/tests/http.test.js +20 -20
  83. package/tests/reactive.test.js +185 -24
  84. package/tests/router.test.js +501 -74
  85. package/tests/ssr.test.js +15 -13
  86. package/tests/store.test.js +264 -23
  87. package/tests/utils.test.js +163 -26
  88. package/types/collection.d.ts +2 -2
  89. package/types/component.d.ts +5 -5
  90. package/types/errors.d.ts +3 -3
  91. package/types/http.d.ts +3 -3
  92. package/types/misc.d.ts +9 -9
  93. package/types/reactive.d.ts +25 -3
  94. package/types/router.d.ts +10 -6
  95. package/types/ssr.d.ts +2 -2
  96. package/types/store.d.ts +40 -5
  97. package/types/utils.d.ts +1 -1
@@ -1,21 +1,21 @@
1
1
  /**
2
- * cli/commands/dev/overlay.js Client-side error overlay + SSE live-reload
2
+ * cli/commands/dev/overlay.js - Client-side error overlay + SSE live-reload
3
3
  *
4
4
  * Returns an HTML <script> snippet that is injected before </body> in
5
5
  * every HTML response served by the dev server. Responsibilities:
6
6
  *
7
- * 1. Error Overlay full-screen dark overlay with code frames, stack
7
+ * 1. Error Overlay - full-screen dark overlay with code frames, stack
8
8
  * traces, and ZQueryError metadata. Dismissable via Esc or ×.
9
- * 2. Runtime error hooks window.onerror, unhandledrejection, AND
9
+ * 2. Runtime error hooks - window.onerror, unhandledrejection, AND
10
10
  * the zQuery $.onError() hook so framework-level errors are
11
11
  * surfaced in the overlay automatically.
12
- * 3. SSE connection listens for reload / css / error:syntax /
12
+ * 3. SSE connection - listens for reload / css / error:syntax /
13
13
  * error:clear events from the dev server watcher.
14
14
  */
15
15
 
16
16
  'use strict';
17
17
 
18
- // The snippet is a self-contained IIFE no external dependencies.
18
+ // The snippet is a self-contained IIFE - no external dependencies.
19
19
  // It must work in all browsers that support EventSource (IE11 excluded).
20
20
 
21
21
  const OVERLAY_SCRIPT = `<script>
@@ -239,7 +239,7 @@ const OVERLAY_SCRIPT = `<script>
239
239
  // Hook into zQuery's $.onError() when the library is loaded
240
240
  // =====================================================================
241
241
  function hookZQueryErrors() {
242
- // $.onError is set by the framework wait for it
242
+ // $.onError is set by the framework - wait for it
243
243
  if (typeof $ !== 'undefined' && typeof $.onError === 'function') {
244
244
  $.onError(function(zqErr) {
245
245
  var data = {
@@ -298,7 +298,7 @@ const OVERLAY_SCRIPT = `<script>
298
298
  });
299
299
 
300
300
  // 2) Try hot-swapping scoped <style data-zq-style-urls> elements
301
- // These come from component styleUrl the CSS was fetched, scoped,
301
+ // These come from component styleUrl - the CSS was fetched, scoped,
302
302
  // and injected as an inline <style>. We re-fetch and re-scope it.
303
303
  if (!matched) {
304
304
  var scopedEls = document.querySelectorAll('style[data-zq-style-urls]');
@@ -315,9 +315,13 @@ const OVERLAY_SCRIPT = `<script>
315
315
 
316
316
  // Re-fetch all style URLs (cache-busted)
317
317
  var urlList = urls.split(' ').filter(Boolean);
318
+ var prevCSS = el.textContent; // preserve current styles as rollback
318
319
  Promise.all(urlList.map(function(u) {
319
320
  return fetch(u + (u.indexOf('?') >= 0 ? '&' : '?') + '_zqr=' + Date.now())
320
- .then(function(r) { return r.text(); });
321
+ .then(function(r) {
322
+ if (!r.ok) throw new Error('CSS fetch failed: ' + r.status);
323
+ return r.text();
324
+ });
321
325
  })).then(function(results) {
322
326
  var raw = (inlineStyles ? inlineStyles + '\\n' : '') + results.join('\\n');
323
327
  // Re-scope CSS with the same scope attribute
@@ -332,11 +336,14 @@ const OVERLAY_SCRIPT = `<script>
332
336
  });
333
337
  }
334
338
  el.textContent = raw;
339
+ }).catch(function() {
340
+ // Restore previous CSS on failure to prevent blank page
341
+ el.textContent = prevCSS;
335
342
  });
336
343
  });
337
344
  }
338
345
 
339
- // 3) Nothing matched fall back to full reload
346
+ // 3) Nothing matched - fall back to full reload
340
347
  if (!matched) { location.reload(); }
341
348
  });
342
349
 
@@ -362,7 +369,7 @@ const OVERLAY_SCRIPT = `<script>
362
369
  connect();
363
370
 
364
371
  // =====================================================================
365
- // Fetch / $.http Interceptor pretty console logging
372
+ // Fetch / $.http Interceptor - pretty console logging
366
373
  // =====================================================================
367
374
  var __zqChannel;
368
375
  try { __zqChannel = new BroadcastChannel('__zq_devtools'); } catch(e) {}
@@ -473,7 +480,7 @@ const OVERLAY_SCRIPT = `<script>
473
480
  };
474
481
 
475
482
  // =====================================================================
476
- // Morph instrumentation hook via window.__zqMorphHook (set by diff.js)
483
+ // Morph instrumentation - hook via window.__zqMorphHook (set by diff.js)
477
484
  // =====================================================================
478
485
  window.__zqMorphHook = function(el, elapsed) {
479
486
  __zqMorphCount++;
@@ -505,7 +512,7 @@ const OVERLAY_SCRIPT = `<script>
505
512
  };
506
513
 
507
514
  // =====================================================================
508
- // Render instrumentation hook for first-renders & route swaps
515
+ // Render instrumentation - hook for first-renders & route swaps
509
516
  // =====================================================================
510
517
  window.__zqRenderHook = function(el, elapsed, kind, name) {
511
518
  __zqRenderCount++;
@@ -538,7 +545,7 @@ const OVERLAY_SCRIPT = `<script>
538
545
  };
539
546
 
540
547
  // =====================================================================
541
- // Router instrumentation history state tracking for devtools
548
+ // Router instrumentation - history state tracking for devtools
542
549
  // =====================================================================
543
550
  var __zqRouterEvents = [];
544
551
 
@@ -613,7 +620,7 @@ const OVERLAY_SCRIPT = `<script>
613
620
  });
614
621
 
615
622
  // =====================================================================
616
- // Dev Toolbar expandable floating bar with stats
623
+ // Dev Toolbar - expandable floating bar with stats
617
624
  // =====================================================================
618
625
  var devBar;
619
626
  var __zqBarExpanded = false;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * cli/commands/dev/server.js HTTP server & SSE broadcasting
2
+ * cli/commands/dev/server.js - HTTP server & SSE broadcasting
3
3
  *
4
4
  * Creates the zero-http app, serves static files, injects the
5
5
  * error-overlay snippet into HTML responses, and manages the
@@ -70,10 +70,10 @@ function promptInstall() {
70
70
 
71
71
  /**
72
72
  * @param {object} opts
73
- * @param {string} opts.root absolute path to project root
74
- * @param {string} opts.htmlEntry e.g. 'index.html'
73
+ * @param {string} opts.root - absolute path to project root
74
+ * @param {string} opts.htmlEntry - e.g. 'index.html'
75
75
  * @param {number} opts.port
76
- * @param {boolean} opts.noIntercept skip zquery.min.js auto-resolve
76
+ * @param {boolean} opts.noIntercept - skip zquery.min.js auto-resolve
77
77
  * @returns {Promise<{ app, pool: SSEPool, listen: Function }>}
78
78
  */
79
79
  async function createServer({ root, htmlEntry, port, noIntercept }) {
@@ -136,7 +136,7 @@ async function createServer({ root, htmlEntry, port, noIntercept }) {
136
136
  // ---- Static files ----
137
137
  app.use(serveStatic(root, { index: false, dotfiles: 'ignore' }));
138
138
 
139
- // ---- SPA fallback inject overlay/SSE snippet ----
139
+ // ---- SPA fallback - inject overlay/SSE snippet ----
140
140
  app.get('*', (req, res) => {
141
141
  if (path.extname(req.url) && path.extname(req.url) !== '.html') {
142
142
  res.status(404).send('Not Found');
@@ -1,5 +1,5 @@
1
1
  /**
2
- * cli/commands/dev/validator.js JS syntax validation
2
+ * cli/commands/dev/validator.js - JS syntax validation
3
3
  *
4
4
  * Pre-validates JavaScript files on save using Node's VM module.
5
5
  * Returns structured error descriptors with code frames compatible
@@ -19,9 +19,9 @@ const vm = require('vm');
19
19
  * Build a code frame showing ~4 lines of context around the error
20
20
  * with a caret pointer at the offending column.
21
21
  *
22
- * @param {string} source full file contents
23
- * @param {number} line 1-based line number
24
- * @param {number} column 1-based column number
22
+ * @param {string} source - full file contents
23
+ * @param {number} line - 1-based line number
24
+ * @param {number} column - 1-based column number
25
25
  * @returns {string}
26
26
  */
27
27
  function generateCodeFrame(source, line, column) {
@@ -52,9 +52,9 @@ function generateCodeFrame(source, line, column) {
52
52
  * Strips ESM import/export statements (preserving line numbers) so the
53
53
  * VM can parse module-style code, then compiles via vm.Script.
54
54
  *
55
- * @param {string} filePath absolute path to the file
56
- * @param {string} relPath display-friendly relative path
57
- * @returns {object|null} error descriptor, or null if valid
55
+ * @param {string} filePath - absolute path to the file
56
+ * @param {string} relPath - display-friendly relative path
57
+ * @returns {object|null} - error descriptor, or null if valid
58
58
  */
59
59
  function validateJS(filePath, relPath) {
60
60
  let source;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * cli/commands/dev/watcher.js File system watcher
2
+ * cli/commands/dev/watcher.js - File system watcher
3
3
  *
4
4
  * Recursively watches the project root for file changes, validates
5
5
  * JS files for syntax errors, and broadcasts reload / CSS hot-swap /
@@ -44,7 +44,7 @@ function collectWatchDirs(dir) {
44
44
  if (!entry.isDirectory() || IGNORE_DIRS.has(entry.name)) continue;
45
45
  dirs.push(...collectWatchDirs(path.join(dir, entry.name)));
46
46
  }
47
- } catch { /* unreadable dir skip */ }
47
+ } catch { /* unreadable dir - skip */ }
48
48
  return dirs;
49
49
  }
50
50
 
@@ -56,8 +56,8 @@ function collectWatchDirs(dir) {
56
56
  * Start watching `root` for file changes.
57
57
  *
58
58
  * @param {object} opts
59
- * @param {string} opts.root absolute project root
60
- * @param {SSEPool} opts.pool SSE broadcast pool
59
+ * @param {string} opts.root - absolute project root
60
+ * @param {SSEPool} opts.pool - SSE broadcast pool
61
61
  * @returns {{ dirs: string[], destroy: Function }}
62
62
  */
63
63
  function startWatcher({ root, pool, bundleMode, serveRoot }) {
@@ -121,7 +121,7 @@ function startWatcher({ root, pool, bundleMode, serveRoot }) {
121
121
  pool.broadcast('error:syntax', JSON.stringify(err));
122
122
  return;
123
123
  }
124
- // File was fixed clear previous overlay
124
+ // File was fixed - clear previous overlay
125
125
  if (currentError === rel) {
126
126
  currentError = null;
127
127
  pool.broadcast('error:clear', '');
@@ -158,7 +158,7 @@ function startWatcher({ root, pool, bundleMode, serveRoot }) {
158
158
  }, 100);
159
159
  });
160
160
  watchers.push(watcher);
161
- } catch { /* dir became inaccessible skip */ }
161
+ } catch { /* dir became inaccessible - skip */ }
162
162
  }
163
163
 
164
164
  function destroy() {
package/cli/help.js CHANGED
@@ -1,4 +1,4 @@
1
- // cli/help.js show CLI usage information
1
+ // cli/help.js - show CLI usage information
2
2
 
3
3
  function showHelp() {
4
4
  console.log(`
@@ -11,7 +11,7 @@ function showHelp() {
11
11
  (defaults to the current directory)
12
12
  --minimal, -m Use the minimal template (home, counter, about)
13
13
  instead of the full-featured default scaffold
14
- --ssr, -s Use the SSR template includes server/index.js
14
+ --ssr, -s Use the SSR template - includes server/index.js
15
15
  SSR HTTP server with shared component definitions
16
16
 
17
17
  dev [root] Start a dev server with live-reload
@@ -69,7 +69,7 @@ function showHelp() {
69
69
  zquery dev --port 8080 custom port
70
70
 
71
71
  The dev server includes a full-screen error overlay:
72
- • JS files are syntax-checked on save errors block reload
72
+ • JS files are syntax-checked on save - errors block reload
73
73
  and show an overlay with exact file, line:column, and code frame
74
74
  • Runtime errors and unhandled rejections are also captured
75
75
  • The overlay auto-clears when the file is fixed and saved
package/cli/index.js CHANGED
@@ -1,7 +1,7 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * zQuery CLI entry point
4
+ * zQuery CLI - entry point
5
5
  *
6
6
  * Dispatches to the appropriate command module under cli/commands/.
7
7
  * Run `zquery --help` for full usage information.
@@ -1,15 +1,15 @@
1
- // app.js Application entry point
1
+ // app.js - Application entry point
2
2
  //
3
3
  // Bootstraps the app: imports components, sets up routing,
4
4
  // wires the responsive sidebar, and connects the store.
5
5
  //
6
6
  // Key APIs used:
7
- // $.router SPA navigation (history mode)
8
- // $.ready run after DOM is loaded
9
- // $.bus event bus (toast notifications, contact card)
10
- // $.on global delegated event listeners
11
- // $.storage localStorage wrapper
12
- // $.create create DOM elements
7
+ // $.router - SPA navigation (history mode)
8
+ // $.ready - run after DOM is loaded
9
+ // $.bus - event bus (toast notifications, contact card)
10
+ // $.on - global delegated event listeners
11
+ // $.storage - localStorage wrapper
12
+ // $.create - create DOM elements
13
13
 
14
14
  import './store.js';
15
15
  import './components/home.js';
@@ -25,16 +25,15 @@ import './components/not-found.js';
25
25
  import { routes } from './routes.js';
26
26
 
27
27
  // ---------------------------------------------------------------------------
28
- // Router SPA navigation with history mode
28
+ // Router - SPA navigation with history mode
29
29
  // ---------------------------------------------------------------------------
30
30
  const router = $.router({
31
- el: '#app', //@ Mount point (Set in index.html)
32
31
  routes,
33
32
  fallback: 'not-found',
34
33
  mode: 'history'
35
34
  });
36
35
 
37
- // Post-navigation hook track page views on every navigation
36
+ // Post-navigation hook - track page views on every navigation
38
37
  router.afterEach((to) => {
39
38
  const store = $.getStore('main');
40
39
  if (store) store.dispatch('incrementVisits');
@@ -65,17 +64,17 @@ function toggleMobileMenu(open) {
65
64
 
66
65
  function closeMobileMenu() { toggleMobileMenu(false); }
67
66
 
68
- // $.on global delegated event listeners
67
+ // $.on - global delegated event listeners
69
68
  $.on('click', '#menu-toggle', () => toggleMobileMenu(!$sidebar.hasClass('open')));
70
69
  $.on('click', '#overlay', closeMobileMenu);
71
70
 
72
- // Close sidebar on Escape key using $.on direct (no selector needed)
71
+ // Close sidebar on Escape key - using $.on direct (no selector needed)
73
72
  $.on('keydown', (e) => {
74
73
  if (e.key === 'Escape') closeMobileMenu();
75
74
  });
76
75
 
77
76
  // ---------------------------------------------------------------------------
78
- // Sidebar stats panel collapsible, live-updating from $.store
77
+ // Sidebar stats panel - collapsible, live-updating from $.store
79
78
  // Starts expanded by default. Open/closed state saved via $.storage.
80
79
  // ---------------------------------------------------------------------------
81
80
  $.on('click', '#stats-toggle', () => {
@@ -100,7 +99,7 @@ function updateSidebarStats() {
100
99
  }
101
100
 
102
101
  // ---------------------------------------------------------------------------
103
- // Sidebar contacts live status indicators from $.store
102
+ // Sidebar contacts - live status indicators from $.store
104
103
  // ---------------------------------------------------------------------------
105
104
  function updateSidebarContacts() {
106
105
  const store = $.getStore('main');
@@ -145,7 +144,7 @@ $.bus.on('toast', ({ message, type = 'info' }) => {
145
144
  });
146
145
 
147
146
  // ---------------------------------------------------------------------------
148
- // On DOM ready final setup
147
+ // On DOM ready - final setup
149
148
  // ---------------------------------------------------------------------------
150
149
  $.ready(() => {
151
150
  // Display version in the sidebar footer
@@ -173,7 +172,7 @@ $.ready(() => {
173
172
  $('#stats-arrow').removeClass('open');
174
173
  }
175
174
 
176
- // Sidebar contact click open the global contact card overlay
175
+ // Sidebar contact click - open the global contact card overlay
177
176
  $('#sc-list').on('click', '.sc-item', (e) => {
178
177
  const item = e.target.closest('.sc-item');
179
178
  if (!item) return;
@@ -193,11 +192,11 @@ $.ready(() => {
193
192
  // Mount any components outside the router outlet (e.g. <contact-card>)
194
193
  $.mountAll();
195
194
 
196
- console.log('⚡ {{NAME}} powered by zQuery v' + $.version);
195
+ console.log('⚡ {{NAME}} - powered by zQuery v' + $.version);
197
196
  });
198
197
 
199
198
  // ---------------------------------------------------------------------------
200
- // Theme helper resolves 'system' to actual dark/light and applies it
199
+ // Theme helper - resolves 'system' to actual dark/light and applies it
201
200
  // ---------------------------------------------------------------------------
202
201
  function applyTheme(preference) {
203
202
  let resolved = preference;
@@ -1,11 +1,11 @@
1
- // about.js About page with theme switcher
1
+ // about.js - About page with theme switcher
2
2
  //
3
3
  // Features used:
4
- // $.storage localStorage wrapper (get / set)
5
- // $.version library version string
6
- // $.unitTests build-time test results object
7
- // $.bus.emit toast notifications
8
- // data-theme attr dark / light theming
4
+ // $.storage - localStorage wrapper (get / set)
5
+ // $.version - library version string
6
+ // $.unitTests - build-time test results object
7
+ // $.bus.emit - toast notifications
8
+ // data-theme attr - dark / light theming
9
9
 
10
10
  $.component('about-page', {
11
11
  styles: `
@@ -100,7 +100,7 @@ $.component('about-page', {
100
100
  'Directives': [
101
101
  ['z-if / z-for / z-show', 'Structural directives for conditional & list rendering'],
102
102
  ['z-bind / z-class / z-style', 'Dynamic attributes, classes, and inline styles'],
103
- ['z-debounce', 'Debounced model updates z-model z-debounce="300"'],
103
+ ['z-debounce', 'Debounced model updates - z-model z-debounce="300"'],
104
104
  ['z-lowercase / z-uppercase', 'Auto-transform text input on contacts email'],
105
105
  ['z-html', 'Trusted HTML injection in the playground'],
106
106
  ['templateUrl / styleUrl', 'External templates and CSS with auto-scoping'],
@@ -109,7 +109,7 @@ $.component('about-page', {
109
109
  ['@click.stop / .prevent', 'Event modifiers for fine-grained control'],
110
110
  ['@click.self / .once', 'Self-only and one-shot handlers in modals'],
111
111
  ['@click.outside', 'Outside-click detection for dropdowns'],
112
- ['@keydown.escape', 'Key modifiers Escape to close forms'],
112
+ ['@keydown.escape', 'Key modifiers - Escape to close forms'],
113
113
  ],
114
114
  'Reactive Primitives': [
115
115
  ['$.signal() / $.computed()', 'Fine-grained reactive primitives for derived state'],
@@ -136,7 +136,7 @@ $.component('about-page', {
136
136
  <div class="about-hero">
137
137
  <span class="ver">v${$.version}</span>
138
138
  <h1>zQuery</h1>
139
- <p>A zero-dependency frontend micro-library reactive components, routing, state management, and more in <strong>${$.libSize}</strong> minified.</p>
139
+ <p>A zero-dependency frontend micro-library - reactive components, routing, state management, and more in <strong>${$.libSize}</strong> minified.</p>
140
140
  </div>
141
141
 
142
142
  <div class="about-stats">
@@ -1,11 +1,11 @@
1
- // api-demo.js HTTP client demo
1
+ // api-demo.js - HTTP client demo
2
2
  //
3
3
  // Features used:
4
- // $.get() fetch JSON from an API
5
- // z-if / z-else / z-show conditional rendering
6
- // z-for / z-text list rendering & text binding
7
- // $.escapeHtml() sanitize user-provided content
8
- // async methods loading & error state patterns
4
+ // $.get() - fetch JSON from an API
5
+ // z-if / z-else / z-show - conditional rendering
6
+ // z-for / z-text - list rendering & text binding
7
+ // $.escapeHtml() - sanitize user-provided content
8
+ // async methods - loading & error state patterns
9
9
 
10
10
  $.component('api-demo', {
11
11
  styles: `
@@ -1,12 +1,12 @@
1
- // contact-card.js Global contact detail popup
1
+ // contact-card.js - Global contact detail popup
2
2
  //
3
3
  // Always-mounted overlay that listens for $.bus 'openContact' events.
4
4
  // Works from any page without navigation.
5
5
  //
6
6
  // Features used:
7
- // $.bus.on / $.bus.emit event-driven communication
8
- // $.getStore read contact data from store
9
- // @click.self dismiss on backdrop click
7
+ // $.bus.on / $.bus.emit - event-driven communication
8
+ // $.getStore - read contact data from store
9
+ // @click.self - dismiss on backdrop click
10
10
 
11
11
  $.component('contact-card', {
12
12
  styles: `
@@ -1,6 +1,6 @@
1
- /* contacts.css scoped styles for contacts-page component
1
+ /* contacts.css - scoped styles for contacts-page component
2
2
  *
3
- * Loaded via styleUrl these styles are automatically scoped
3
+ * Loaded via styleUrl - these styles are automatically scoped
4
4
  * to the contacts-page component by zQuery.
5
5
  */
6
6
 
@@ -1,5 +1,5 @@
1
1
  <!--
2
- contacts.html external template for contacts-page component
2
+ contacts.html - external template for contacts-page component
3
3
 
4
4
  This template is fetched via templateUrl and uses {{expression}} syntax
5
5
  for data binding. All zQuery directives work here: z-if, z-else,
@@ -10,7 +10,7 @@
10
10
  <h1>Contacts</h1>
11
11
  <p class="subtitle">
12
12
  External template &amp; styles via <code>templateUrl</code> / <code>styleUrl</code>.
13
- Click a contact card to open the detail modal dismiss with <code>Esc</code> or <code>@click.outside</code>.
13
+ Click a contact card to open the detail modal - dismiss with <code>Esc</code> or <code>@click.outside</code>.
14
14
  </p>
15
15
  </div>
16
16
 
@@ -74,7 +74,7 @@
74
74
  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor" style="width:48px;height:48px;opacity:.3;"><path stroke-linecap="round" stroke-linejoin="round" d="M15 9h3.75M15 12h3.75M15 15h3.75M4.5 19.5h15a2.25 2.25 0 0 0 2.25-2.25V6.75A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25v10.5A2.25 2.25 0 0 0 4.5 19.5Zm6-10.125a1.875 1.875 0 1 1-3.75 0 1.875 1.875 0 0 1 3.75 0Zm1.294 6.336a6.721 6.721 0 0 1-3.17.789 6.721 6.721 0 0 1-3.168-.789 3.376 3.376 0 0 1 6.338 0Z"/></svg>
75
75
  </div>
76
76
  <p z-if="filterText || filterRole">No contacts match your filter.</p>
77
- <p z-else>No contacts yet hit <strong>+ Add Contact</strong> to create one!</p>
77
+ <p z-else>No contacts yet - hit <strong>+ Add Contact</strong> to create one!</p>
78
78
  </div>
79
79
 
80
80
  <!-- ═══ Add Contact Modal ═══ -->
@@ -1,13 +1,13 @@
1
- // contacts.js Contact book page
1
+ // contacts.js - Contact book page
2
2
  //
3
3
  // Features used:
4
- // templateUrl / styleUrl external template & scoped styles
5
- // z-if / z-show / z-for conditional & list rendering
6
- // z-model / z-ref form bindings
7
- // @click / @submit.prevent event handling
8
- // @keydown.escape keyboard modifier
9
- // $.getStore / dispatch store integration
10
- // $.bus.emit('toast') notifications
4
+ // templateUrl / styleUrl - external template & scoped styles
5
+ // z-if / z-show / z-for - conditional & list rendering
6
+ // z-model / z-ref - form bindings
7
+ // @click / @submit.prevent - event handling
8
+ // @keydown.escape - keyboard modifier
9
+ // $.getStore / dispatch - store integration
10
+ // $.bus.emit('toast') - notifications
11
11
 
12
12
  $.component('contacts-page', {
13
13
  templateUrl: 'contacts.html',
@@ -29,7 +29,7 @@ $.component('contacts-page', {
29
29
  favoriteCount: 0,
30
30
  filterText: '',
31
31
  filterRole: '',
32
- // Derived state (not computed external templates resolve state only)
32
+ // Derived state (not computed - external templates resolve state only)
33
33
  filteredContacts: [],
34
34
  modalContact: null,
35
35
  }),
@@ -45,7 +45,7 @@ $.component('contacts-page', {
45
45
  this._syncFromStore(store);
46
46
  this._unsub = store.subscribe(() => this._syncFromStore(store));
47
47
 
48
- // Global Escape handler template @keydown.escape on overlays is
48
+ // Global Escape handler - template @keydown.escape on overlays is
49
49
  // unreliable when no child element has focus (detail modal has no inputs).
50
50
  this._onEscape = (e) => {
51
51
  if (e.key !== 'Escape') return;
@@ -62,7 +62,7 @@ $.component('contacts-page', {
62
62
 
63
63
  _syncFromStore(store) {
64
64
  // Shallow-clone each contact so the framework detects new references
65
- // (store actions mutate objects in place same refs won't trigger re-render)
65
+ // (store actions mutate objects in place - same refs won't trigger re-render)
66
66
  this.state.contacts = store.state.contacts.map(c => ({ ...c }));
67
67
  this.state.totalAdded = store.state.contactsAdded;
68
68
  this.state.favoriteCount = store.getters.favoriteCount;
@@ -1,11 +1,11 @@
1
- // counter.js Interactive counter
1
+ // counter.js - Interactive counter
2
2
  //
3
3
  // Features used:
4
- // state / computed / watch reactive data flow
5
- // @click event binding
6
- // z-model + z-number two-way binding with type coercion
7
- // z-class / z-if / z-for conditional & list rendering
8
- // $.bus.emit('toast', …) notifications via event bus
4
+ // state / computed / watch - reactive data flow
5
+ // @click - event binding
6
+ // z-model + z-number - two-way binding with type coercion
7
+ // z-class / z-if / z-for - conditional & list rendering
8
+ // $.bus.emit('toast', …) - notifications via event bus
9
9
 
10
10
  $.component('counter-page', {
11
11
  styles: `
@@ -72,7 +72,7 @@ $.component('counter-page', {
72
72
 
73
73
  decrement() {
74
74
  this.state.count -= this.state.step;
75
- this._pushHistory('', this.state.step, this.state.count);
75
+ this._pushHistory('-', this.state.step, this.state.count);
76
76
  },
77
77
 
78
78
  _pushHistory(action, value, result) {
@@ -101,7 +101,7 @@ $.component('counter-page', {
101
101
  </div>
102
102
 
103
103
  <div class="ctr-actions">
104
- <button class="btn btn-outline" @click="decrement">− Subtract</button>
104
+ <button class="btn btn-outline" @click="decrement">- Subtract</button>
105
105
  <button class="btn btn-primary" @click="increment">+ Add</button>
106
106
  </div>
107
107
 
@@ -1,11 +1,11 @@
1
- // home.js Landing page / dashboard
1
+ // home.js - Landing page / dashboard
2
2
  //
3
3
  // Features used:
4
- // $.component define a component with state + render
5
- // $.signal reactive value container
6
- // $.computed derived reactive value
7
- // $.effect side-effect that auto-tracks signals
8
- // $.getStore access the global store
4
+ // $.component - define a component with state + render
5
+ // $.signal - reactive value container
6
+ // $.computed - derived reactive value
7
+ // $.effect - side-effect that auto-tracks signals
8
+ // $.getStore - access the global store
9
9
 
10
10
  $.component('home-page', {
11
11
  styles: `
@@ -136,7 +136,7 @@ $.component('home-page', {
136
136
  render() {
137
137
  const store = $.getStore('main');
138
138
  const s = this.state;
139
- const opLabels = { add: '+', subtract: '', multiply: '×', divide: '÷', power: '^', modulo: '%' };
139
+ const opLabels = { add: '+', subtract: '-', multiply: '×', divide: '÷', power: '^', modulo: '%' };
140
140
  const maxH = Math.max(1, ...s.sigHistory.map(v => Math.sqrt(Math.abs(v) + 1)));
141
141
  return `
142
142
  <div class="page-header">
@@ -146,13 +146,13 @@ $.component('home-page', {
146
146
 
147
147
  <div class="card card-accent">
148
148
  <h3><svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="var(--accent)" style="width:20px;height:20px;vertical-align:-4px;margin-right:0.25rem;"><path stroke-linecap="round" stroke-linejoin="round" d="m3.75 13.5 10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75Z"/></svg> Reactive Signals Lab</h3>
149
- <p style="margin-bottom:.65rem;">Signals are <strong>reactive primitives</strong> values that automatically notify dependents when they change.
149
+ <p style="margin-bottom:.65rem;">Signals are <strong>reactive primitives</strong> - values that automatically notify dependents when they change.
150
150
  Adjust <strong>A</strong> and <strong>B</strong> below and watch the computed result update instantly, with no manual DOM wiring.</p>
151
151
 
152
152
  <div class="sig-lab">
153
153
  <div class="sig-row">
154
154
  <div class="sig-op">
155
- <button class="btn btn-sm btn-ghost" @click="bumpA(-1)">−</button>
155
+ <button class="btn btn-sm btn-ghost" @click="bumpA(-1)">-</button>
156
156
  <div class="sig-val"><small>A</small> <span>${s.sigA}</span></div>
157
157
  <button class="btn btn-sm btn-ghost" @click="bumpA(1)">+</button>
158
158
  </div>
@@ -170,7 +170,7 @@ $.component('home-page', {
170
170
  </div>
171
171
  </div>
172
172
  <div class="sig-op">
173
- <button class="btn btn-sm btn-ghost" @click="bumpB(-1)">−</button>
173
+ <button class="btn btn-sm btn-ghost" @click="bumpB(-1)">-</button>
174
174
  <div class="sig-val"><small>B</small> <span>${s.sigB}</span></div>
175
175
  <button class="btn btn-sm btn-ghost" @click="bumpB(1)">+</button>
176
176
  </div>
@@ -186,7 +186,7 @@ $.component('home-page', {
186
186
  <div class="sig-graph">
187
187
  ${s.sigHistory.map(v => `<div class="sig-bar" style="height:${Math.max(6, (Math.sqrt(Math.abs(v) + 1) / maxH) * 56)}px;"></div>`).join('')}
188
188
  </div>
189
- <div style="font-size:.75rem;color:var(--text-muted);margin-top:.35rem;">Result history ${s.sigHistory.length} values tracked by <code>effect()</code></div>
189
+ <div style="font-size:.75rem;color:var(--text-muted);margin-top:.35rem;">Result history - ${s.sigHistory.length} values tracked by <code>effect()</code></div>
190
190
  ` : ''}
191
191
  </div>
192
192
 
@@ -197,11 +197,11 @@ $.component('home-page', {
197
197
  </div>
198
198
  <div class="sig-concept">
199
199
  <h4>Computed</h4>
200
- <p>A derived value that re-evaluates when its dependencies change. <code>$.computed(() => A + B)</code> recalculates whenever A or B updates no manual calls.</p>
200
+ <p>A derived value that re-evaluates when its dependencies change. <code>$.computed(() => A + B)</code> recalculates whenever A or B updates - no manual calls.</p>
201
201
  </div>
202
202
  <div class="sig-concept">
203
203
  <h4>Effect</h4>
204
- <p>A side-effect that runs automatically when tracked signals change. The bar chart above is powered by <code>$.effect()</code> it records every new result.</p>
204
+ <p>A side-effect that runs automatically when tracked signals change. The bar chart above is powered by <code>$.effect()</code> - it records every new result.</p>
205
205
  </div>
206
206
  </div>
207
207
  </div>