zero-query 0.9.9 → 1.0.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.
Files changed (99) hide show
  1. package/README.md +34 -33
  2. package/cli/args.js +1 -1
  3. package/cli/commands/build.js +2 -2
  4. package/cli/commands/bundle.js +21 -18
  5. package/cli/commands/create.js +9 -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 +1 -1
  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 +2 -2
  53. package/cli/scaffold/ssr/app/routes.js +1 -1
  54. package/cli/scaffold/ssr/global.css +3 -4
  55. package/cli/scaffold/ssr/index.html +2 -2
  56. package/cli/scaffold/ssr/server/index.js +26 -25
  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 +3 -3
  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/test-minifier.js +153 -0
  88. package/tests/test-ssr.js +27 -0
  89. package/tests/utils.test.js +163 -26
  90. package/types/collection.d.ts +2 -2
  91. package/types/component.d.ts +5 -5
  92. package/types/errors.d.ts +3 -3
  93. package/types/http.d.ts +3 -3
  94. package/types/misc.d.ts +9 -9
  95. package/types/reactive.d.ts +25 -3
  96. package/types/router.d.ts +10 -6
  97. package/types/ssr.d.ts +2 -2
  98. package/types/store.d.ts +40 -5
  99. package/types/utils.d.ts +1 -1
@@ -1,4 +1,4 @@
1
- // not-found.js 404 fallback page
1
+ // not-found.js - 404 fallback page
2
2
  //
3
3
  // Uses $.getRouter() to display the unmatched path.
4
4
 
@@ -1,4 +1,4 @@
1
- /* playground.css scoped styles for the playground page component */
1
+ /* playground.css - scoped styles for the playground page component */
2
2
 
3
3
  .pg-section { display: flex; align-items: center; gap: .5rem;
4
4
  font-size: .72rem; font-weight: 600; text-transform: uppercase;
@@ -1,12 +1,12 @@
1
1
  <!--
2
- playground.html external template for playground-page component
2
+ playground.html - external template for playground-page component
3
3
 
4
- Interactive UI patterns event modifiers, animations, reactive bindings,
4
+ Interactive UI patterns - event modifiers, animations, reactive bindings,
5
5
  and plugins. Uses {{expression}} syntax for data binding.
6
6
  -->
7
7
  <div class="page-header" z-cloak>
8
8
  <h1>Playground</h1>
9
- <p class="subtitle">Interactive UI patterns event modifiers, animations, reactive bindings, and plugins.</p>
9
+ <p class="subtitle">Interactive UI patterns - event modifiers, animations, reactive bindings, and plugins.</p>
10
10
  </div>
11
11
 
12
12
  <!-- ── Interaction Patterns ──────────────────────────── -->
@@ -14,7 +14,7 @@
14
14
 
15
15
  <div class="card" style="position:relative;z-index:2;">
16
16
  <h3>Dropdown → Modal Flow</h3>
17
- <p>Select an action from the <code>@click.outside</code> dropdown it opens a confirmation modal. Dismiss via overlay (<code>@click.self</code>) or <kbd style="padding:.1rem .35rem;background:var(--bg-hover);border-radius:4px;font-size:.82rem;">Esc</kbd>.</p>
17
+ <p>Select an action from the <code>@click.outside</code> dropdown - it opens a confirmation modal. Dismiss via overlay (<code>@click.self</code>) or <kbd style="padding:.1rem .35rem;background:var(--bg-hover);border-radius:4px;font-size:.82rem;">Esc</kbd>.</p>
18
18
  <div style="display:flex;align-items:center;gap:1rem;flex-wrap:wrap;">
19
19
  <div class="pg-dropdown" @click.outside="closeDropdown">
20
20
  <button class="btn btn-primary" @click="toggleDropdown">
@@ -30,7 +30,7 @@
30
30
  <button z-else class="btn btn-ghost" disabled>✓ Once fired</button>
31
31
  </div>
32
32
 
33
- <!-- Modal faded in via JS, dismissed via overlay @click.self or Escape -->
33
+ <!-- Modal - faded in via JS, dismissed via overlay @click.self or Escape -->
34
34
  <div class="pg-modal-backdrop" z-if="modalOpen" style="display:none" @click.self="closeModal">
35
35
  <div class="pg-modal" @keydown.escape="closeModal" tabindex="-1">
36
36
  <h3>Confirm: <span z-text="dropdownSelected || 'Action'"></span></h3>
@@ -57,7 +57,7 @@
57
57
  <span id="pg-acc-icon-a" class="pg-accordion-icon">▸</span>
58
58
  </button>
59
59
  <div id="pg-acc-a" style="display:none">
60
- <div class="pg-accordion-body">A zero-dependency frontend library for reactive SPAs components, routing, stores, HTTP, and 200+ utilities in one ~28 KB file.</div>
60
+ <div class="pg-accordion-body">A zero-dependency frontend library for reactive SPAs - components, routing, stores, HTTP, and 200+ utilities in one ~28 KB file.</div>
61
61
  </div>
62
62
  </div>
63
63
  <div class="pg-accordion-item">
@@ -87,7 +87,7 @@
87
87
  <div class="card-grid">
88
88
  <div class="card">
89
89
  <h3>Dynamic Styles</h3>
90
- <p>Object binding via <code>z-style</code> inline styles update reactively.</p>
90
+ <p>Object binding via <code>z-style</code> - inline styles update reactively.</p>
91
91
  <div class="pg-style-preview" z-style="{ color: previewColor, fontSize: previewSize + 'px', borderRadius: previewRadius + 'px', borderColor: previewColor }">
92
92
  Live Preview
93
93
  </div>
@@ -100,14 +100,14 @@
100
100
 
101
101
  <div class="card">
102
102
  <h3>Rich Content</h3>
103
- <p>Render trusted HTML with <code>z-html</code> only use with sanitized content.</p>
103
+ <p>Render trusted HTML with <code>z-html</code> - only use with sanitized content.</p>
104
104
  <textarea z-model="richContent" class="input" rows="2" style="resize:vertical;"></textarea>
105
105
  <div class="pg-rich-preview" style="margin-top:.5rem;" z-html="richContent"></div>
106
106
  </div>
107
107
 
108
108
  <div class="card">
109
109
  <h3>Conditional Classes</h3>
110
- <p>Switch a single class from a set using <code>z-class</code> the object syntax applies only the matching key.</p>
110
+ <p>Switch a single class from a set using <code>z-class</code> - the object syntax applies only the matching key.</p>
111
111
  <div class="pg-variant-row">
112
112
  <div class="pg-variant-box" z-class="{'info': variant === 'info', 'success': variant === 'success', 'warning': variant === 'warning', 'danger': variant === 'danger'}">
113
113
  {{variant.charAt(0).toUpperCase() + variant.slice(1)}} Variant
@@ -128,7 +128,7 @@
128
128
 
129
129
  <div class="card">
130
130
  <h3>Key &amp; System Modifiers</h3>
131
- <p>Template-level keyboard filtering no manual <code>e.key</code> checks needed.</p>
131
+ <p>Template-level keyboard filtering - no manual <code>e.key</code> checks needed.</p>
132
132
  <div style="display:flex;gap:.5rem;flex-wrap:wrap;align-items:center;">
133
133
  <input type="text" class="input input-sm" placeholder="Press Enter…" @keyup.enter="logShortcut('Enter ↵')" style="flex:1;min-width:140px;" />
134
134
  <button class="btn btn-sm btn-outline" @click.ctrl="logShortcut('Ctrl+Click')">Ctrl+Click</button>
@@ -144,7 +144,7 @@
144
144
  <div class="pg-section">Plugin System</div>
145
145
 
146
146
  <div class="card">
147
- <h3><code>$.fn</code> Extend the Collection</h3>
147
+ <h3><code>$.fn</code> - Extend the Collection</h3>
148
148
  <p>Register custom chainable methods on every <code>$(...)</code> selection. Click the buttons to trigger each plugin.</p>
149
149
  <div id="pg-plugin-box" class="pg-plugin-target">✦ Target Element</div>
150
150
  <div class="pg-plugin-btns">
@@ -1,14 +1,14 @@
1
- // playground.js Interactive UI patterns
1
+ // playground.js - Interactive UI patterns
2
2
  //
3
3
  // Features used:
4
- // @click.outside / .self / .once event modifiers
5
- // @keydown.escape / @keyup.enter keyboard modifiers
6
- // fadeIn / fadeOut / slideToggle DOM animations
7
- // z-style reactive inline styles
8
- // z-html trusted HTML rendering
9
- // $.fn collection plugin system
10
- // z-skip morph opt-out
11
- // templateUrl / styleUrl external files
4
+ // @click.outside / .self / .once - event modifiers
5
+ // @keydown.escape / @keyup.enter - keyboard modifiers
6
+ // fadeIn / fadeOut / slideToggle - DOM animations
7
+ // z-style - reactive inline styles
8
+ // z-html - trusted HTML rendering
9
+ // $.fn - collection plugin system
10
+ // z-skip - morph opt-out
11
+ // templateUrl / styleUrl - external files
12
12
 
13
13
  // ── $.fn Plugins ─────────────────────────────────────────────────
14
14
  $.fn.highlight = function (color = 'var(--accent)') {
@@ -88,7 +88,7 @@ $.component('playground-page', {
88
88
  $.bus.emit('toast', { message: `${item} confirmed!`, type: 'success' });
89
89
  },
90
90
 
91
- /* Accordion pure DOM, z-skip prevents morph interference */
91
+ /* Accordion - pure DOM, z-skip prevents morph interference */
92
92
  toggleAccordion(id) {
93
93
  $(this._el).find(`#pg-acc-${id}`).slideToggle(250);
94
94
  $(this._el).find(`#pg-acc-icon-${id}`).toggleClass('open');
@@ -112,6 +112,6 @@ $.component('playground-page', {
112
112
  /* @click.once */
113
113
  onceAction() {
114
114
  this.state.onceClicked = true;
115
- $.bus.emit('toast', { message: 'Fired once handler auto-removed!', type: 'info' });
115
+ $.bus.emit('toast', { message: 'Fired once - handler auto-removed!', type: 'info' });
116
116
  },
117
117
  });
@@ -1,12 +1,12 @@
1
- // todos.js Todo list with global store
1
+ // todos.js - Todo list with global store
2
2
  //
3
3
  // Features used:
4
- // $.getStore / dispatch / subscribe centralized state management
5
- // z-model / z-ref form bindings
6
- // z-for + z-key keyed list rendering with diffing
7
- // z-class / z-if / z-show conditional rendering
8
- // @submit.prevent / @keydown.escape event modifiers
9
- // mounted / destroyed lifecycle setup & teardown
4
+ // $.getStore / dispatch / subscribe - centralized state management
5
+ // z-model / z-ref - form bindings
6
+ // z-for + z-key - keyed list rendering with diffing
7
+ // z-class / z-if / z-show - conditional rendering
8
+ // @submit.prevent / @keydown.escape - event modifiers
9
+ // mounted / destroyed lifecycle - setup & teardown
10
10
 
11
11
  $.component('todos-page', {
12
12
  styles: `
@@ -204,7 +204,7 @@ $.component('todos-page', {
204
204
 
205
205
  <div z-if="filtered.length === 0" class="td-empty">
206
206
  <div class="td-empty-icon">${this.state.total === 0 ? '📝' : '🔍'}</div>
207
- <p>${this.state.total === 0 ? 'No todos yet type something above and hit Add!' : 'No matching todos for this filter.'}</p>
207
+ <p>${this.state.total === 0 ? 'No todos yet - type something above and hit Add!' : 'No matching todos for this filter.'}</p>
208
208
  </div>
209
209
 
210
210
  <ul z-else class="td-list">
@@ -1,4 +1,4 @@
1
- /* toolkit.css scoped styles for the toolkit page component */
1
+ /* toolkit.css - scoped styles for the toolkit page component */
2
2
 
3
3
  .tk-tabs { display: flex; padding: .35rem;
4
4
  background: var(--bg-surface);
@@ -1,5 +1,5 @@
1
1
  <!--
2
- toolkit.html external template for toolkit-page component
2
+ toolkit.html - external template for toolkit-page component
3
3
 
4
4
  HTTP client with interceptors, 30+ utility functions, and advanced
5
5
  store patterns. Uses {{expression}} syntax and z-if / z-for / z-show.
@@ -65,7 +65,7 @@
65
65
  <div z-else-if="activeTab === 'utils'">
66
66
  <div class="card">
67
67
  <h3>Utility Belt</h3>
68
- <p>30+ built-in helpers select a category to run a live demo.</p>
68
+ <p>30+ built-in helpers - select a category to run a live demo.</p>
69
69
 
70
70
  <div class="tk-util-grid">
71
71
  <div class="tk-util-card {{activeUtil === 'pipe' ? 'selected' : ''}}" @click="runUtil('pipe')">
@@ -102,7 +102,7 @@
102
102
  <div z-else>
103
103
  <div class="card" style="margin-bottom:.75rem;">
104
104
  <h3>Store Inspector</h3>
105
- <p>Live view into the reactive store middleware, snapshots, and action history.</p>
105
+ <p>Live view into the reactive store - middleware, snapshots, and action history.</p>
106
106
 
107
107
  <div style="display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem;">
108
108
  <div class="tk-stat">
@@ -134,7 +134,7 @@
134
134
 
135
135
  <div class="card card-muted" z-show="storeLog.length > 0">
136
136
  <h3>Middleware Log</h3>
137
- <p style="color:var(--text-muted);font-size:.85rem;margin-bottom:.5rem;">Real-time log from <code>store.use()</code> interact with other pages to generate entries.</p>
137
+ <p style="color:var(--text-muted);font-size:.85rem;margin-bottom:.5rem;">Real-time log from <code>store.use()</code> - interact with other pages to generate entries.</p>
138
138
  <div class="tk-log">
139
139
  <div z-for="entry in storeLog" z-key="{{entry.id}}" class="tk-log-entry">
140
140
  <span style="color:var(--text-muted);font-size:.78rem;min-width:65px;">{{entry.time}}</span>
@@ -1,11 +1,11 @@
1
- // toolkit.js HTTP, utilities, and advanced store features
1
+ // toolkit.js - HTTP, utilities, and advanced store features
2
2
  //
3
3
  // Features used:
4
- // $.http / $.post / $.put / $.delete HTTP client + interceptors
5
- // $.pipe / $.memoize / $.retry functional utilities
6
- // $.groupBy / $.chunk / $.unique collection helpers
7
- // store.use / snapshot / history middleware & time-travel
8
- // templateUrl / styleUrl external template & styles
4
+ // $.http / $.post / $.put / $.delete - HTTP client + interceptors
5
+ // $.pipe / $.memoize / $.retry - functional utilities
6
+ // $.groupBy / $.chunk / $.unique - collection helpers
7
+ // store.use / snapshot / history - middleware & time-travel
8
+ // templateUrl / styleUrl - external template & styles
9
9
 
10
10
  $.component('toolkit-page', {
11
11
  templateUrl: 'toolkit.html',
@@ -32,7 +32,7 @@ $.component('toolkit-page', {
32
32
  actionCount: 0,
33
33
  }),
34
34
 
35
- // init() lifecycle runs before the first render
35
+ // init() lifecycle - runs before the first render
36
36
  init() {
37
37
  this._prevBaseURL = $.http.getConfig().baseURL || '';
38
38
  $.http.configure({ baseURL: 'https://jsonplaceholder.typicode.com' });
@@ -1,4 +1,4 @@
1
- // routes.js Route definitions
1
+ // routes.js - Route definitions
2
2
  //
3
3
  // Maps URL paths to component tag names.
4
4
  // Also supports :params, wildcards, and lazy loading via `load`.
@@ -1,4 +1,4 @@
1
- // store.js Global state management
1
+ // store.js - Global state management
2
2
  //
3
3
  // Defines a centralized store with state, actions, and getters.
4
4
  // Any component can access it via $.getStore('main').
@@ -1,4 +1,4 @@
1
- /* global.css responsive scaffold styles
1
+ /* global.css - responsive scaffold styles
2
2
  *
3
3
  * Uses CSS custom properties for easy theming. Feel free to modify.
4
4
  * Dark theme by default, light theme via [data-theme="light"].
@@ -504,7 +504,7 @@ code { background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-s
504
504
  @keyframes toast-out { from { opacity: 1; transform: translateY(0) scale(1); } to { opacity: 0; transform: translateY(-10px) scale(0.95); } }
505
505
 
506
506
  /* -- Route Transition -- */
507
- #app { animation: fade-in 0.25s var(--ease-out); }
507
+ z-outlet { display: block; animation: fade-in 0.25s var(--ease-out); }
508
508
  @keyframes fade-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
509
509
 
510
510
  /* -- Responsive: Mobile -- */
@@ -86,8 +86,8 @@
86
86
  <div class="overlay" id="overlay"></div>
87
87
 
88
88
  <!-- @ Router Outlet @ -->
89
- <main class="content" id="app"></main>
90
- <!-- @ Mount point is set in app/app.js @ -->
89
+ <z-outlet class="content"></z-outlet>
90
+ <!-- @ Auto-detected by $.router() @ -->
91
91
 
92
92
  <!-- Toast container for notifications -->
93
93
  <div class="toast-container" id="toasts"></div>
@@ -1,13 +1,13 @@
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
  // and wires the responsive sidebar.
5
5
  //
6
6
  // Key APIs used:
7
- // $.router SPA navigation (history mode)
8
- // $.ready run after DOM is loaded
9
- // $.on global delegated event listeners
10
- // $.storage localStorage wrapper
7
+ // $.router - SPA navigation (history mode)
8
+ // $.ready - run after DOM is loaded
9
+ // $.on - global delegated event listeners
10
+ // $.storage - localStorage wrapper
11
11
 
12
12
  import './store.js';
13
13
  import './components/home.js';
@@ -20,7 +20,6 @@ import { routes } from './routes.js';
20
20
  // Router
21
21
  // ---------------------------------------------------------------------------
22
22
  const router = $.router({
23
- el: '#app',
24
23
  routes,
25
24
  fallback: 'not-found',
26
25
  mode: 'history'
@@ -75,7 +74,7 @@ $.ready(() => {
75
74
  const current = window.location.pathname;
76
75
  $.all(`.nav-link[z-link="${current}"]`).addClass('active');
77
76
 
78
- console.log('⚡ {{NAME}} powered by zQuery v' + $.version);
77
+ console.log('⚡ {{NAME}} - powered by zQuery v' + $.version);
79
78
  });
80
79
 
81
80
  // ---------------------------------------------------------------------------
@@ -1,9 +1,9 @@
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
- // data-theme dark / light theming
4
+ // $.storage - localStorage wrapper (get / set)
5
+ // $.version - library version string
6
+ // data-theme - dark / light theming
7
7
 
8
8
  $.component('about-page', {
9
9
  styles: `
@@ -40,7 +40,7 @@ $.component('about-page', {
40
40
  return `
41
41
  <div class="page-header">
42
42
  <h1>About</h1>
43
- <p class="subtitle">zQuery v${$.version} zero-dependency frontend micro-library.</p>
43
+ <p class="subtitle">zQuery v${$.version} - zero-dependency frontend micro-library.</p>
44
44
  </div>
45
45
 
46
46
  <div class="card">
@@ -1,9 +1,9 @@
1
- // counter.js Interactive counter
1
+ // counter.js - Interactive counter
2
2
  //
3
3
  // Features used:
4
- // $.getStore / store.subscribe shared state + live re-render
5
- // @click / z-model + z-number events + two-way binding
6
- // z-if / z-for / z-key conditional & keyed list rendering
4
+ // $.getStore / store.subscribe - shared state + live re-render
5
+ // @click / z-model + z-number - events + two-way binding
6
+ // z-if / z-for / z-key - conditional & keyed list rendering
7
7
 
8
8
  $.component('counter-page', {
9
9
  styles: `
@@ -62,7 +62,7 @@ $.component('counter-page', {
62
62
  decrement() {
63
63
  const store = $.getStore('main');
64
64
  store.dispatch('decrement');
65
- this._pushHistory('', store.state.step, store.state.count);
65
+ this._pushHistory('-', store.state.step, store.state.count);
66
66
  },
67
67
 
68
68
  setStep(e) {
@@ -96,7 +96,7 @@ $.component('counter-page', {
96
96
  </div>
97
97
 
98
98
  <div class="ctr-actions">
99
- <button class="btn btn-outline" @click="decrement">− Subtract</button>
99
+ <button class="btn btn-outline" @click="decrement">- Subtract</button>
100
100
  <button class="btn btn-primary" @click="increment">+ Add</button>
101
101
  </div>
102
102
 
@@ -1,10 +1,10 @@
1
- // home.js Landing page
1
+ // home.js - Landing page
2
2
  //
3
3
  // Features used:
4
- // $.component define a component
5
- // $.getStore read/dispatch global store
6
- // store.subscribe re-render on store changes
7
- // @click / z-model event binding + two-way input
4
+ // $.component - define a component
5
+ // $.getStore - read/dispatch global store
6
+ // store.subscribe - re-render on store changes
7
+ // @click / z-model - event binding + two-way input
8
8
 
9
9
  $.component('home-page', {
10
10
  state: () => ({
@@ -41,7 +41,7 @@ $.component('home-page', {
41
41
  <div class="card">
42
42
  <h3>Getting Started</h3>
43
43
  <p>
44
- This is the <strong>minimal</strong> scaffold three pages, a global store,
44
+ This is the <strong>minimal</strong> scaffold - three pages, a global store,
45
45
  and the router. Edit the files in <code>app/</code> to start building.
46
46
  </p>
47
47
  <p>
@@ -52,9 +52,9 @@ $.component('home-page', {
52
52
 
53
53
  <div class="card">
54
54
  <h3>Global Store</h3>
55
- <p>The counter from <a z-link="/counter">Counter</a> is backed by <code>$.store</code> its value persists across pages:</p>
55
+ <p>The counter from <a z-link="/counter">Counter</a> is backed by <code>$.store</code> - its value persists across pages:</p>
56
56
  <div style="display:flex;align-items:center;gap:.75rem;margin-top:.75rem;">
57
- <button class="btn btn-outline btn-sm" @click="decrement">−</button>
57
+ <button class="btn btn-outline btn-sm" @click="decrement">-</button>
58
58
  <span style="font-size:1.25rem;font-weight:700;color:var(--accent);min-width:2rem;text-align:center;">${count}</span>
59
59
  <button class="btn btn-primary btn-sm" @click="increment">+</button>
60
60
  <button class="btn btn-outline btn-sm" @click="reset" style="margin-left:.5rem;">Reset</button>
@@ -1,4 +1,4 @@
1
- // not-found.js 404 fallback page
1
+ // not-found.js - 404 fallback page
2
2
  //
3
3
  // Uses $.getRouter() to display the unmatched path.
4
4
 
@@ -1,4 +1,4 @@
1
- // routes.js Route definitions
1
+ // routes.js - Route definitions
2
2
  //
3
3
  // Maps URL paths to component tag names.
4
4
 
@@ -1,4 +1,4 @@
1
- // store.js Global state management
1
+ // store.js - Global state management
2
2
  //
3
3
  // A simple centralized store. Any component can access it
4
4
  // via $.getStore('main') and dispatch actions to update state.
@@ -1,4 +1,4 @@
1
- /* global.css minimal scaffold styles
1
+ /* global.css - minimal scaffold styles
2
2
  *
3
3
  * Dark theme by default, light theme via [data-theme="light"].
4
4
  * Modify the CSS variables below to customise the look and feel.
@@ -259,7 +259,7 @@ code { background: var(--bg-hover); padding: 2px 6px; border-radius: 4px; font-s
259
259
  .muted { color: var(--text-muted); }
260
260
 
261
261
  /* -- Route Transition -- */
262
- #app { animation: fade-in 0.25s var(--ease-out); }
262
+ z-outlet { display: block; animation: fade-in 0.25s var(--ease-out); }
263
263
  @keyframes fade-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
264
264
 
265
265
  /* -- Responsive: Mobile -- */
@@ -38,7 +38,7 @@
38
38
  <div class="overlay" id="overlay"></div>
39
39
 
40
40
  <!-- Router Outlet -->
41
- <main class="content" id="app"></main>
41
+ <z-outlet class="content"></z-outlet>
42
42
 
43
43
  </body>
44
44
  </html>
@@ -1,4 +1,4 @@
1
- // app.js Client entry point
1
+ // app.js - Client entry point
2
2
  //
3
3
  // Imports shared component definitions and registers them with zQuery.
4
4
  // The SSR server imports the same definitions via createSSRApp().
@@ -15,7 +15,6 @@ $.component('not-found', notFound);
15
15
 
16
16
  // Client-side router
17
17
  const router = $.router({
18
- el: '#app',
19
18
  routes,
20
19
  fallback: 'not-found',
21
20
  mode: 'history'
@@ -1,12 +1,12 @@
1
- // about.js About page component
1
+ // about.js - About page component
2
2
 
3
3
  export const aboutPage = {
4
4
  state: () => ({
5
5
  features: [
6
- 'createSSRApp() isolated component registry for Node.js',
7
- 'renderToString() render a component to an HTML string',
8
- 'renderPage() full HTML document with meta tags',
9
- 'renderBatch() render multiple components in one call',
6
+ 'createSSRApp() - isolated component registry for Node.js',
7
+ 'renderToString() - render a component to an HTML string',
8
+ 'renderPage() - full HTML document with meta tags',
9
+ 'renderBatch() - render multiple components in one call',
10
10
  'Hydration markers (data-zq-ssr) for client takeover',
11
11
  'SEO: description, canonical URL, Open Graph tags',
12
12
  ]
@@ -1,4 +1,4 @@
1
- // home.js Home page component
1
+ // home.js - Home page component
2
2
  //
3
3
  // Exports a plain definition object that works on both client and server.
4
4
  // The client registers it with $.component(), the server with app.component().
@@ -9,7 +9,7 @@ export const homePage = {
9
9
  timestamp: new Date().toLocaleTimeString(),
10
10
  }),
11
11
 
12
- // init() runs on both client and server no DOM required
12
+ // init() runs on both client and server - no DOM required
13
13
  init() {
14
14
  const hour = new Date().getHours();
15
15
  this.state.greeting =
@@ -1,4 +1,4 @@
1
- // not-found.js 404 fallback component
1
+ // not-found.js - 404 fallback component
2
2
 
3
3
  export const notFound = {
4
4
  render() {
@@ -7,7 +7,7 @@ export const notFound = {
7
7
  <h1>404</h1>
8
8
  <p class="subtitle">Page not found.</p>
9
9
  <p style="margin-top:1rem;">
10
- <a href="/" style="color:var(--accent);">← Home</a>
10
+ <a z-link="/" style="color:var(--accent);">← Home</a>
11
11
  </p>
12
12
  </div>
13
13
  `;
@@ -1,4 +1,4 @@
1
- // routes.js Route definitions (shared between client and server)
1
+ // routes.js - Route definitions (shared between client and server)
2
2
 
3
3
  export const routes = [
4
4
  { path: '/', component: 'home-page' },
@@ -1,4 +1,4 @@
1
- /* global.css SSR Scaffold Styles */
1
+ /* global.css - SSR Scaffold Styles */
2
2
 
3
3
  *, *::before, *::after {
4
4
  box-sizing: border-box;
@@ -56,14 +56,13 @@ body {
56
56
  }
57
57
 
58
58
  /* -- Main content -- */
59
- #app {
59
+ z-outlet {
60
+ display: block;
60
61
  max-width: 800px;
61
62
  margin: 2rem auto;
62
63
  padding: 0 1.5rem;
63
64
  }
64
65
 
65
- [z-cloak] { display: none !important; }
66
-
67
66
  .page-header {
68
67
  margin-bottom: var(--gap);
69
68
  }
@@ -20,8 +20,8 @@
20
20
  </div>
21
21
  </nav>
22
22
 
23
- <!-- Main content SSR output is injected here by the server -->
24
- <main id="app" z-cloak></main>
23
+ <!-- Main content - SSR output is injected here by the server -->
24
+ <z-outlet></z-outlet>
25
25
 
26
26
  <footer class="footer">
27
27
  <small>Built with zQuery · SSR Scaffold</small>