jsgui3-server 0.0.149 → 0.0.151
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/.github/agents/Mobile Developer.agent.md +89 -0
- package/.github/instructions/copilot.instructions.md +1 -0
- package/AGENTS.md +6 -0
- package/README.md +185 -0
- package/admin-ui/client.js +73 -43
- package/admin-ui/v1/admin_auth_service.js +197 -0
- package/admin-ui/v1/admin_user_store.js +71 -0
- package/admin-ui/v1/client.js +17 -0
- package/admin-ui/v1/controls/admin_shell.js +1399 -0
- package/admin-ui/v1/controls/group_box.js +84 -0
- package/admin-ui/v1/controls/stat_card.js +125 -0
- package/admin-ui/v1/server.js +658 -0
- package/admin-ui/v1/utils/formatters.js +68 -0
- package/docs/admin-extension-guide.md +345 -0
- package/docs/api-reference.md +383 -303
- package/docs/books/adaptive-control-improvements/01-control-candidate-matrix.md +122 -0
- package/docs/books/adaptive-control-improvements/02-tier-1-layout-playbooks.md +207 -0
- package/docs/books/adaptive-control-improvements/03-tier-2-navigation-form-overlay.md +140 -0
- package/docs/books/adaptive-control-improvements/04-cross-cutting-platform-functionality.md +141 -0
- package/docs/books/adaptive-control-improvements/05-styling-theming-density-upgrades.md +114 -0
- package/docs/books/adaptive-control-improvements/06-testing-quality-gates.md +97 -0
- package/docs/books/adaptive-control-improvements/07-delivery-roadmap-and-ownership.md +137 -0
- package/docs/books/adaptive-control-improvements/08-appendix-tier1-acceptance-and-pr-templates.md +261 -0
- package/docs/books/adaptive-control-improvements/README.md +66 -0
- package/docs/books/admin-ui-authentication/01-threat-model-and-goals.md +124 -0
- package/docs/books/admin-ui-authentication/02-session-model-and-token-model.md +75 -0
- package/docs/books/admin-ui-authentication/03-auth-middleware-patterns.md +77 -0
- package/docs/books/admin-ui-authentication/README.md +25 -0
- package/docs/books/creating-a-new-admin-ui/01-introduction-and-vision.md +130 -0
- package/docs/books/creating-a-new-admin-ui/02-architecture-and-data-flow.md +298 -0
- package/docs/books/creating-a-new-admin-ui/03-server-introspection.md +381 -0
- package/docs/books/creating-a-new-admin-ui/04-admin-module-adapter-layer.md +592 -0
- package/docs/books/creating-a-new-admin-ui/05-domain-controls-stat-cards-and-gauges.md +513 -0
- package/docs/books/creating-a-new-admin-ui/06-domain-controls-process-manager.md +544 -0
- package/docs/books/creating-a-new-admin-ui/07-domain-controls-resource-pool-inspector.md +493 -0
- package/docs/books/creating-a-new-admin-ui/08-domain-controls-route-table-and-api-explorer.md +586 -0
- package/docs/books/creating-a-new-admin-ui/09-domain-controls-log-viewer-and-activity-feed.md +490 -0
- package/docs/books/creating-a-new-admin-ui/10-domain-controls-build-status-and-bundle-inspector.md +526 -0
- package/docs/books/creating-a-new-admin-ui/11-domain-controls-configuration-panel.md +808 -0
- package/docs/books/creating-a-new-admin-ui/12-admin-shell-layout-sidebar-navigation.md +210 -0
- package/docs/books/creating-a-new-admin-ui/13-telemetry-integration.md +556 -0
- package/docs/books/creating-a-new-admin-ui/14-realtime-sse-observable-integration.md +485 -0
- package/docs/books/creating-a-new-admin-ui/15-styling-theming-aero-design-system.md +521 -0
- package/docs/books/creating-a-new-admin-ui/16-testing-and-quality-assurance.md +147 -0
- package/docs/books/creating-a-new-admin-ui/17-next-steps-process-resource-roadmap.md +356 -0
- package/docs/books/creating-a-new-admin-ui/README.md +68 -0
- package/docs/books/device-adaptive-composition/01-platform-feature-audit.md +177 -0
- package/docs/books/device-adaptive-composition/02-responsive-composition-model.md +187 -0
- package/docs/books/device-adaptive-composition/03-data-model-vs-view-model.md +231 -0
- package/docs/books/device-adaptive-composition/04-styling-theme-breakpoints.md +234 -0
- package/docs/books/device-adaptive-composition/05-showcase-app-multi-device-assessment.md +193 -0
- package/docs/books/device-adaptive-composition/06-implementation-patterns-and-apis.md +346 -0
- package/docs/books/device-adaptive-composition/07-testing-harness-and-quality-gates.md +265 -0
- package/docs/books/device-adaptive-composition/08-roadmap-and-adoption-plan.md +250 -0
- package/docs/books/device-adaptive-composition/README.md +47 -0
- package/docs/comparison-report-express-plex-cpanel.md +549 -0
- package/docs/comprehensive-documentation.md +220 -220
- package/docs/configuration-reference.md +227 -204
- package/docs/designs/server-admin-interface-aero.svg +611 -0
- package/docs/middleware-guide.md +236 -0
- package/docs/system-architecture.md +24 -18
- package/docs/troubleshooting.md +84 -53
- package/middleware/compression.js +217 -0
- package/middleware/index.js +15 -0
- package/module.js +19 -11
- package/package.json +1 -1
- package/serve-factory.js +29 -0
- package/server.js +280 -20
- package/tests/README.md +5 -0
- package/tests/admin-ui-jsgui-controls.test.js +581 -0
- package/tests/test-runner.js +1 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-071799b982906680f5fd699d.js +0 -40
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-07352945ad5c92654fcb8b65.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-138a601fadb6191ea314c6fd.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-171f6c381c2cadf2e9fa7087.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-1d973388156b84a04373fac9.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-20e117bc8a10d2cd16234bbe.js +0 -40
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-2b028a82b0e5efddba42425f.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-4518556cd5c7e059e82b22b8.js +0 -40
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-5bac1aa0f213902f718ed74f.js +0 -40
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-5f9996ac7822caf777d92f56.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-60a92c702e65fd9cf748e3ec.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-6164c1f8f738995c541895d2.js +0 -44
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-6718a85eb9e5aa782dd47a05.js +0 -45
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-69e280f14e37aee76a1d4675.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7570d1b030d44b111ed59c4c.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7798c9bbd55e510d5039f936.js +0 -42
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-78cd511ea1ef18ecb03d1be5.js +0 -40
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7d482e0b95bcb5e3c543118b.js +0 -43
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-80e9476d1127c55b40fdb36f.js +0 -40
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-810ced55d5320a3088a05b13.js +0 -40
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-8423565f1a40e329afc8c6cf.js +0 -40
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-900bef783b8cee36506ec282.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-a1a37aff6416fdad74040ddf.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-ad48d5e8eda40f175b4df090.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-aec5a2d963015528c9099462.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-af9d34e0f1722fab9e28c269.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-b818e4015e2f1fe86280b5ab.js +0 -41
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-bcb2541adc70b7aba61768c5.js +0 -44
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-bfe89d2c78ed44f95ed7dd73.js +0 -40
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-c06f04806a1e688e1187110c.js +0 -40
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-c3f3adf904f585afc544b96a.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-d45acb873e1d8e32d5e60f2e.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-db06f132533706f4a0163b8c.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-f660f40d78b135fc8560a862.js +0 -39
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-f9dee4ec18a96e09bee06bae.js +0 -39
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# Chapter 7 — Testing Harness and Quality Gates
|
|
2
|
+
|
|
3
|
+
## Why Responsive Testing Must Be Explicit
|
|
4
|
+
|
|
5
|
+
A control can pass every interaction test at 1280×900 and still be broken on a phone. Buttons overlap, text overflows, drawers fail to open, keyboard paths become incomplete. These are not edge cases — they affect real users on real devices.
|
|
6
|
+
|
|
7
|
+
The jsgui3 test suite currently validates rich interactivity across 14+ Playwright suites, all running at a single viewport size. This chapter defines how to extend that coverage to a **viewport matrix** — running key tests across multiple screen dimensions and verifying that adaptive behavior works correctly at each size.
|
|
8
|
+
|
|
9
|
+
## The Viewport Matrix
|
|
10
|
+
|
|
11
|
+
### Minimum Required Profiles
|
|
12
|
+
|
|
13
|
+
Every responsive test suite should exercise these six profiles:
|
|
14
|
+
|
|
15
|
+
| Profile | Width × Height | Represents |
|
|
16
|
+
|---------|---------------|------------|
|
|
17
|
+
| Phone portrait | 390 × 844 | iPhone 14, typical Android |
|
|
18
|
+
| Phone landscape | 844 × 390 | iPhone 14 rotated |
|
|
19
|
+
| Tablet portrait | 768 × 1024 | iPad, Surface Go portrait |
|
|
20
|
+
| Tablet landscape | 1024 × 768 | iPad landscape |
|
|
21
|
+
| Desktop narrow | 1280 × 720 | Laptop, resized browser |
|
|
22
|
+
| Desktop wide | 1920 × 1080 | Full HD monitor |
|
|
23
|
+
|
|
24
|
+
### Optional Extended Profiles
|
|
25
|
+
|
|
26
|
+
For thorough coverage, add:
|
|
27
|
+
|
|
28
|
+
| Profile | Width × Height | Represents |
|
|
29
|
+
|---------|---------------|------------|
|
|
30
|
+
| Phone small | 320 × 568 | iPhone SE, older Android |
|
|
31
|
+
| Tablet large | 1024 × 1366 | iPad Pro 12.9″ portrait |
|
|
32
|
+
| Desktop 4K | 2560 × 1440 | High-resolution desktop |
|
|
33
|
+
| Embedded narrow | 400 × 600 | Widget in a sidebar |
|
|
34
|
+
|
|
35
|
+
## Assertion Categories
|
|
36
|
+
|
|
37
|
+
For each viewport profile, tests should cover these categories, ordered by priority:
|
|
38
|
+
|
|
39
|
+
### P0: Layout Integrity
|
|
40
|
+
|
|
41
|
+
The most fundamental check — does the layout work at this size?
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
// No horizontal overflow
|
|
45
|
+
const body_width = await page.evaluate(() => document.body.scrollWidth);
|
|
46
|
+
const viewport_width = page.viewportSize().width;
|
|
47
|
+
assert(body_width <= viewport_width + 1, 'No horizontal overflow');
|
|
48
|
+
|
|
49
|
+
// Key containers are visible
|
|
50
|
+
const content = await page.$('.content-area');
|
|
51
|
+
const box = await content.boundingBox();
|
|
52
|
+
assert(box.width > 100, 'Content area has reasonable width');
|
|
53
|
+
assert(box.height > 50, 'Content area has reasonable height');
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### P0: Interaction Integrity
|
|
57
|
+
|
|
58
|
+
Controls remain usable — clickable, focusable, and responsive:
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
// Buttons are clickable (not obscured, not zero-size)
|
|
62
|
+
const buttons = await page.$$('button');
|
|
63
|
+
for (const btn of buttons) {
|
|
64
|
+
const box = await btn.boundingBox();
|
|
65
|
+
if (box) {
|
|
66
|
+
assert(box.width >= 20, `Button width >= 20px`);
|
|
67
|
+
assert(box.height >= 20, `Button height >= 20px`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Interactive elements respond to clicks
|
|
72
|
+
await page.click('.tab-label:first-child');
|
|
73
|
+
await delay(200);
|
|
74
|
+
const active = await page.$eval('.tab-label:first-child input', el => el.checked);
|
|
75
|
+
assert(active, 'Tab responds to click at this viewport');
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### P1: Adaptive Morphing
|
|
79
|
+
|
|
80
|
+
If the app uses compose_adaptive or region morphing, verify the correct structure appears:
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
// At phone width: navigation should be a drawer, not inline
|
|
84
|
+
if (profile.name === 'phone_portrait') {
|
|
85
|
+
const drawer = await page.$('.drawer');
|
|
86
|
+
assert(drawer, 'Navigation renders as drawer on phone');
|
|
87
|
+
const sidebar = await page.$('.nav-sidebar');
|
|
88
|
+
assert(!sidebar, 'No inline sidebar on phone');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// At desktop width: navigation should be inline sidebar
|
|
92
|
+
if (profile.name === 'desktop_wide') {
|
|
93
|
+
const sidebar = await page.$('.nav-sidebar');
|
|
94
|
+
assert(sidebar, 'Navigation renders as sidebar on desktop');
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### P1: Accessibility Integrity
|
|
99
|
+
|
|
100
|
+
Keyboard navigation and ARIA attributes remain correct across sizes:
|
|
101
|
+
|
|
102
|
+
```js
|
|
103
|
+
// Focus is reachable for all interactive elements
|
|
104
|
+
const focusable = await page.$$('button, a[href], input, select, textarea, [tabindex="0"]');
|
|
105
|
+
assert(focusable.length > 0, 'Has focusable elements');
|
|
106
|
+
|
|
107
|
+
// ARIA roles are present (not removed by adaptive composition)
|
|
108
|
+
const tabs = await page.$$('[role="tab"]');
|
|
109
|
+
if (tabs.length > 0) {
|
|
110
|
+
const aria = await tabs[0].getAttribute('aria-selected');
|
|
111
|
+
assert(aria !== null, 'Tab has aria-selected attribute');
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### P2: Visual Integrity
|
|
116
|
+
|
|
117
|
+
Token-driven styling applies correctly:
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
// Theme tokens are applied (not broken by mode switch)
|
|
121
|
+
const bg = await page.$eval('body', el => getComputedStyle(el).backgroundColor);
|
|
122
|
+
assert(bg !== '', 'Body has background color');
|
|
123
|
+
|
|
124
|
+
// Touch targets meet minimum size on touch profiles
|
|
125
|
+
if (profile.interaction_mode === 'touch') {
|
|
126
|
+
const buttons = await page.$$('button');
|
|
127
|
+
for (const btn of buttons) {
|
|
128
|
+
const box = await btn.boundingBox();
|
|
129
|
+
if (box) {
|
|
130
|
+
assert(box.height >= 44, `Touch target >= 44px`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Practical Harness Pattern
|
|
137
|
+
|
|
138
|
+
### Viewport Matrix Runner
|
|
139
|
+
|
|
140
|
+
The existing Playwright test pattern uses self-contained test files with HTTP servers. Extend this with a viewport loop:
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
const VIEWPORTS = [
|
|
144
|
+
{ name: 'phone_portrait', width: 390, height: 844 },
|
|
145
|
+
{ name: 'phone_landscape', width: 844, height: 390 },
|
|
146
|
+
{ name: 'tablet_portrait', width: 768, height: 1024 },
|
|
147
|
+
{ name: 'tablet_landscape', width: 1024, height: 768 },
|
|
148
|
+
{ name: 'desktop_narrow', width: 1280, height: 720 },
|
|
149
|
+
{ name: 'desktop_wide', width: 1920, height: 1080 }
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
async function run_viewport_matrix(page, assertions_fn) {
|
|
153
|
+
const results = [];
|
|
154
|
+
|
|
155
|
+
for (const vp of VIEWPORTS) {
|
|
156
|
+
await page.setViewportSize({ width: vp.width, height: vp.height });
|
|
157
|
+
await delay(300); // Allow layout reflow and adaptive recomposition
|
|
158
|
+
|
|
159
|
+
console.log(`\n── ${vp.name} (${vp.width}×${vp.height}) ──`);
|
|
160
|
+
|
|
161
|
+
const vp_results = await assertions_fn(page, vp);
|
|
162
|
+
results.push({ viewport: vp.name, ...vp_results });
|
|
163
|
+
|
|
164
|
+
// Capture screenshot for visual spot-check
|
|
165
|
+
await page.screenshot({
|
|
166
|
+
path: path.join(SCREENSHOT_DIR, `${test_name}-${vp.name}.png`),
|
|
167
|
+
fullPage: true
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return results;
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Integration with Existing Test Runner
|
|
176
|
+
|
|
177
|
+
The aggregate runner at `test/e2e/playwright/run_all_playwright.js` can include viewport-matrix tests as additional suites. Each adaptive control gets its own matrix test file:
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
test/e2e/playwright/
|
|
181
|
+
showcase_app.e2e.playwright.js ← existing (single viewport)
|
|
182
|
+
showcase_app_responsive.e2e.playwright.js ← NEW (viewport matrix)
|
|
183
|
+
drawer_responsive.e2e.playwright.js ← NEW (Drawer adaptation)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Screenshot Artifacts
|
|
187
|
+
|
|
188
|
+
Each viewport capture goes to a `screenshots/` directory next to the test file, named with the viewport profile:
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
screenshots/
|
|
192
|
+
showcase-phone_portrait.png
|
|
193
|
+
showcase-phone_landscape.png
|
|
194
|
+
showcase-tablet_portrait.png
|
|
195
|
+
showcase-tablet_landscape.png
|
|
196
|
+
showcase-desktop_narrow.png
|
|
197
|
+
showcase-desktop_wide.png
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
These serve as visual regression baselines. They're not pixel-compared automatically (brittle), but they provide quick human review for unexpected layout changes.
|
|
201
|
+
|
|
202
|
+
## Quality Gates
|
|
203
|
+
|
|
204
|
+
### Gate Levels
|
|
205
|
+
|
|
206
|
+
| Gate | Scope | When |
|
|
207
|
+
|------|-------|------|
|
|
208
|
+
| P0 Gate | Layout + interaction integrity at all 6 viewports | Every PR that touches layout or composition |
|
|
209
|
+
| P1 Gate | Adaptive morphing + accessibility at all 6 viewports | Every PR that touches adaptive controls |
|
|
210
|
+
| P2 Gate | Visual integrity + touch targets at all 6 viewports | Before releases |
|
|
211
|
+
|
|
212
|
+
### Definition of "Responsive Green"
|
|
213
|
+
|
|
214
|
+
A control suite is "responsive green" when:
|
|
215
|
+
|
|
216
|
+
1. Zero horizontal overflow at any viewport
|
|
217
|
+
2. All interactive elements remain clickable/focusable
|
|
218
|
+
3. Adaptive morphing produces the correct structure per mode
|
|
219
|
+
4. No uncaught errors in any viewport profile
|
|
220
|
+
5. Screenshots captured successfully for visual review
|
|
221
|
+
|
|
222
|
+
### Incremental Adoption
|
|
223
|
+
|
|
224
|
+
Not every test suite needs viewport-matrix coverage immediately. The priority order:
|
|
225
|
+
|
|
226
|
+
1. **Showcase app** — the reference implementation, highest priority
|
|
227
|
+
2. **Shell/navigation controls** — Drawer, Tabbed_Panel, Accordion
|
|
228
|
+
3. **Data-dense controls** — tables, forms, editors
|
|
229
|
+
4. **Utility controls** — modals, tooltips, popovers
|
|
230
|
+
5. **Atomic controls** — buttons, inputs, chips (usually correct by token inheritance)
|
|
231
|
+
|
|
232
|
+
## Testing the Environment Service Itself
|
|
233
|
+
|
|
234
|
+
The View Environment Service (Pattern 1 from Chapter 6) should have its own unit tests:
|
|
235
|
+
|
|
236
|
+
```js
|
|
237
|
+
// Test: mode resolution from viewport width
|
|
238
|
+
const env = new View_Environment({ defaults: { layout_mode: 'desktop' } });
|
|
239
|
+
env._resolve_from_viewport(390, 844);
|
|
240
|
+
assert(env.state.layout_mode === 'phone');
|
|
241
|
+
assert(env.state.viewport.orientation === 'portrait');
|
|
242
|
+
|
|
243
|
+
env._resolve_from_viewport(1024, 768);
|
|
244
|
+
assert(env.state.layout_mode === 'desktop');
|
|
245
|
+
assert(env.state.viewport.orientation === 'landscape');
|
|
246
|
+
|
|
247
|
+
// Test: change events fire correctly
|
|
248
|
+
let change_count = 0;
|
|
249
|
+
env.on('change:layout_mode', () => change_count++);
|
|
250
|
+
env._resolve_from_viewport(390, 844);
|
|
251
|
+
env._resolve_from_viewport(1920, 1080);
|
|
252
|
+
assert(change_count === 2);
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Summary
|
|
256
|
+
|
|
257
|
+
Responsive testing is not optional — it's a quality gate. The existing Playwright infrastructure is well-suited for viewport-matrix extension. The key additions are:
|
|
258
|
+
|
|
259
|
+
1. A standard set of viewport profiles
|
|
260
|
+
2. A `run_viewport_matrix()` utility for looping tests across sizes
|
|
261
|
+
3. Prioritized assertion categories (P0/P1/P2)
|
|
262
|
+
4. Screenshot artifacts for visual review
|
|
263
|
+
5. Incremental adoption from showcase → shells → data controls → utilities
|
|
264
|
+
|
|
265
|
+
**Next:** [Chapter 8](08-roadmap-and-adoption-plan.md) puts everything together into a phased adoption plan.
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# Chapter 8 — Roadmap and Adoption Plan
|
|
2
|
+
|
|
3
|
+
## Guiding Principle
|
|
4
|
+
|
|
5
|
+
Ship value incrementally. Each phase should produce usable outcomes — not just infrastructure that waits for future phases to become useful. Every phase ends with working code, passing tests, and updated documentation.
|
|
6
|
+
|
|
7
|
+
## Phase A: Standardize Environment Vocabulary
|
|
8
|
+
|
|
9
|
+
**Goal:** Establish a shared language so all controls and apps use the same terms for the same concepts.
|
|
10
|
+
|
|
11
|
+
### Deliverables
|
|
12
|
+
|
|
13
|
+
1. **Canonical mode taxonomy document** — formal definitions of:
|
|
14
|
+
- Layout modes: `phone` (≤599px), `tablet` (600–1023px), `desktop` (≥1024px)
|
|
15
|
+
- Density modes: `compact`, `cozy` (default), `comfortable`
|
|
16
|
+
- Interaction modes: `touch`, `pointer`, `hybrid`
|
|
17
|
+
- Motion modes: `normal`, `reduced`
|
|
18
|
+
|
|
19
|
+
2. **Root-level mode attributes** — CSS and JS both reference:
|
|
20
|
+
- `data-layout-mode` on `<html>` or `<body>`
|
|
21
|
+
- `data-density-mode`
|
|
22
|
+
- `data-interaction-mode`
|
|
23
|
+
|
|
24
|
+
3. **Density token override CSS** — a small CSS file that overrides `--j-space-*` and `--admin-*` tokens per density mode (as described in Chapter 4).
|
|
25
|
+
|
|
26
|
+
### Estimated Effort
|
|
27
|
+
|
|
28
|
+
Small. Mostly documentation and a CSS file. No runtime code changes.
|
|
29
|
+
|
|
30
|
+
### Outcome
|
|
31
|
+
|
|
32
|
+
Every developer and every control has a common vocabulary. CSS selectors like `[data-layout-mode="phone"]` work immediately, even before the environment service exists, because developers can set the attributes manually for testing.
|
|
33
|
+
|
|
34
|
+
### Dependencies
|
|
35
|
+
|
|
36
|
+
None. This can start today.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Phase B: Ship Adaptive Helper APIs
|
|
41
|
+
|
|
42
|
+
**Goal:** Provide the runtime infrastructure so controls can respond to environment changes.
|
|
43
|
+
|
|
44
|
+
### Deliverables
|
|
45
|
+
|
|
46
|
+
1. **`View_Environment` service** — the observer class described in Chapter 6, Pattern 1:
|
|
47
|
+
- Viewport observation with debounced resize handling
|
|
48
|
+
- Mode resolution from configurable breakpoints
|
|
49
|
+
- Change events for layout, density, interaction, and motion modes
|
|
50
|
+
- SSR-safe defaults
|
|
51
|
+
- Sets root-level data attributes from Phase A
|
|
52
|
+
|
|
53
|
+
2. **`compose_adaptive()` helper** — the composition branching utility from Chapter 6, Pattern 2:
|
|
54
|
+
- Reads layout_mode, calls matching branch
|
|
55
|
+
- Registers change listener for recomposition
|
|
56
|
+
- Handles fallback (tablet → phone → desktop)
|
|
57
|
+
- Returns cleanup function
|
|
58
|
+
|
|
59
|
+
3. **Responsive param branch support in `theme_params`** — Chapter 6, Pattern 3:
|
|
60
|
+
- Accept mode-keyed param objects
|
|
61
|
+
- Auto-resolve based on current layout_mode
|
|
62
|
+
- Re-resolve on mode change
|
|
63
|
+
|
|
64
|
+
### Estimated Effort
|
|
65
|
+
|
|
66
|
+
Medium. View_Environment is ~150 lines. compose_adaptive is ~60 lines. Param branching is a modest extension to existing theme_params resolver.
|
|
67
|
+
|
|
68
|
+
### Outcome
|
|
69
|
+
|
|
70
|
+
App developers can write `compose_adaptive(this, { phone, tablet, desktop })` and get correct behavior. The boilerplate for responsive composition drops from ~30 lines per control to ~5 lines.
|
|
71
|
+
|
|
72
|
+
### Dependencies
|
|
73
|
+
|
|
74
|
+
Phase A (vocabulary must be defined before the service uses it).
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Phase C: Upgrade Control Catalog Incrementally
|
|
79
|
+
|
|
80
|
+
**Goal:** Make existing controls responsive-aware, prioritized by impact.
|
|
81
|
+
|
|
82
|
+
### Priority Tiers
|
|
83
|
+
|
|
84
|
+
**Tier 1: Shell and navigation** (highest impact — these define app structure)
|
|
85
|
+
|
|
86
|
+
| Control | Adaptation |
|
|
87
|
+
|---------|-----------|
|
|
88
|
+
| Drawer | Already has breakpoint support; wire to View_Environment instead of manual resize |
|
|
89
|
+
| Tabbed_Panel | Overflow-scroll on phone when tabs > 4; vertical tabs on narrow embedded |
|
|
90
|
+
| Accordion | Becomes primary navigation pattern on phone |
|
|
91
|
+
| Stack | No changes needed (already flexible); document responsive patterns |
|
|
92
|
+
|
|
93
|
+
**Tier 2: Data-dense controls** (high visibility in admin/dashboard apps)
|
|
94
|
+
|
|
95
|
+
| Control | Adaptation |
|
|
96
|
+
|---------|-----------|
|
|
97
|
+
| Data tables | Column reduction via responsive params; card layout option for phone |
|
|
98
|
+
| Forms | Single-column on phone; multi-column on desktop |
|
|
99
|
+
| Code_Editor | Full-bleed on phone; constrained width on desktop |
|
|
100
|
+
| Filter_Chips | Horizontal scroll strip on narrow; wrapped on wide |
|
|
101
|
+
|
|
102
|
+
**Tier 3: Utility and overlay controls**
|
|
103
|
+
|
|
104
|
+
| Control | Adaptation |
|
|
105
|
+
|---------|-----------|
|
|
106
|
+
| Drawer (overlay variant) | Already works; ensure touch dismissal |
|
|
107
|
+
| Modals/dialogs | Full-screen on phone; centered constrained on desktop |
|
|
108
|
+
| Tooltips | Suppress on touch (use bottom sheet or inline); show on pointer |
|
|
109
|
+
| Split_Pane | Disable resize handle on phone (stack instead) |
|
|
110
|
+
|
|
111
|
+
**Tier 4: Atomic controls** (lowest priority — usually correct via token inheritance)
|
|
112
|
+
|
|
113
|
+
| Control | Adaptation |
|
|
114
|
+
|---------|-----------|
|
|
115
|
+
| Buttons | Touch target enforcement via density tokens |
|
|
116
|
+
| Inputs | Larger padding/height via density tokens |
|
|
117
|
+
| Chips, badges | Usually fine at all sizes |
|
|
118
|
+
|
|
119
|
+
### Approach
|
|
120
|
+
|
|
121
|
+
Each control upgrade follows the same pattern:
|
|
122
|
+
1. Add responsive params if needed
|
|
123
|
+
2. Use `compose_adaptive()` for structural changes (or skip if CSS-only adaptation suffices)
|
|
124
|
+
3. Wire to View_Environment instead of manual `window.innerWidth`
|
|
125
|
+
4. Add viewport-matrix test assertions
|
|
126
|
+
5. Update control documentation
|
|
127
|
+
|
|
128
|
+
### Estimated Effort
|
|
129
|
+
|
|
130
|
+
Large overall, but each individual control is small (hours, not days). Can be done incrementally by different contributors.
|
|
131
|
+
|
|
132
|
+
### Dependencies
|
|
133
|
+
|
|
134
|
+
Phase B (helpers must exist before controls use them).
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Phase D: Formalize Responsive Test Suites
|
|
139
|
+
|
|
140
|
+
**Goal:** Make responsive testing a first-class quality gate.
|
|
141
|
+
|
|
142
|
+
### Deliverables
|
|
143
|
+
|
|
144
|
+
1. **`run_viewport_matrix()` test utility** — the shared function from Chapter 7 that loops tests across 6 viewport profiles.
|
|
145
|
+
|
|
146
|
+
2. **Viewport-matrix tests** for each Tier 1 and Tier 2 control:
|
|
147
|
+
- Showcase app responsive suite
|
|
148
|
+
- Drawer responsive suite
|
|
149
|
+
- Tabbed_Panel responsive suite
|
|
150
|
+
- Data table responsive suite
|
|
151
|
+
|
|
152
|
+
3. **Screenshot baseline directory** — organized per-control, per-viewport screenshots checked into the repo for visual regression review.
|
|
153
|
+
|
|
154
|
+
4. **CI integration** — responsive suites run in the aggregate test runner alongside existing tests.
|
|
155
|
+
|
|
156
|
+
### Estimated Effort
|
|
157
|
+
|
|
158
|
+
Medium. The utility is small (~50 lines). Each control's responsive test is ~100 lines (mostly reusing the single-viewport test with a viewport loop wrapper).
|
|
159
|
+
|
|
160
|
+
### Outcome
|
|
161
|
+
|
|
162
|
+
Responsive regressions are caught before merge. No more "it works on my desktop" issues.
|
|
163
|
+
|
|
164
|
+
### Dependencies
|
|
165
|
+
|
|
166
|
+
Phase C (controls must be adaptive before their responsive tests can verify adaptation). However, the showcase app responsive test can ship with Phase B, since the showcase manually implements adaptive patterns.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Phase E: Showcase App as Reference Implementation
|
|
171
|
+
|
|
172
|
+
**Goal:** The showcase app demonstrates every adaptive pattern, serving as both a demo and a regression test.
|
|
173
|
+
|
|
174
|
+
### Deliverables
|
|
175
|
+
|
|
176
|
+
1. **Adaptive showcase composition** — the showcase app uses `compose_adaptive()` for its shell layout, demonstrating:
|
|
177
|
+
- 3-column → 2-column → 1-column shell transitions
|
|
178
|
+
- Nav sidebar → pill bar → drawer morphing
|
|
179
|
+
- Theme studio → slide-over → presets-only adaptation
|
|
180
|
+
|
|
181
|
+
2. **Theme profile persistence** — the showcase uses full theme profiles (theme + density + overrides) with export/import.
|
|
182
|
+
|
|
183
|
+
3. **Responsive Playwright suite** — 6-viewport test covering all showcase sections.
|
|
184
|
+
|
|
185
|
+
4. **Documentation** — the showcase README documents every adaptive pattern used, linking back to the relevant book chapter.
|
|
186
|
+
|
|
187
|
+
### Estimated Effort
|
|
188
|
+
|
|
189
|
+
Medium. Most of the work is refactoring the existing showcase composition to use the new helpers.
|
|
190
|
+
|
|
191
|
+
### Outcome
|
|
192
|
+
|
|
193
|
+
New developers can look at the showcase app and see: "this is how you build a responsive jsgui3 app." Every pattern from this book is demonstrated in working code.
|
|
194
|
+
|
|
195
|
+
### Dependencies
|
|
196
|
+
|
|
197
|
+
Phases A–D. This is the capstone.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Phase Dependency Map
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
Phase A (Vocabulary)
|
|
205
|
+
↓
|
|
206
|
+
Phase B (Helper APIs) ──→ Phase D.1 (Showcase responsive test)
|
|
207
|
+
↓
|
|
208
|
+
Phase C (Controls) ──→ Phase D (Full test suites)
|
|
209
|
+
↓
|
|
210
|
+
Phase E (Showcase reference)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Phases A and B are sequential prerequisites. Phase C and D overlap — as each control is upgraded, its test is written. Phase E comes last.
|
|
214
|
+
|
|
215
|
+
## Recommended Near-Term Backlog
|
|
216
|
+
|
|
217
|
+
Starting from zero, the highest-value first steps are:
|
|
218
|
+
|
|
219
|
+
| # | Task | Phase | Why First |
|
|
220
|
+
|---|------|-------|-----------|
|
|
221
|
+
| 1 | Define mode taxonomy in docs | A | Foundation — everything references these terms |
|
|
222
|
+
| 2 | Write density-mode CSS overrides | A | Immediately usable in any app |
|
|
223
|
+
| 3 | Implement `View_Environment` service | B | Unlocks all adaptive patterns |
|
|
224
|
+
| 4 | Implement `compose_adaptive()` helper | B | Biggest developer productivity gain |
|
|
225
|
+
| 5 | Add viewport-matrix test for showcase | D.1 | Proves the test harness works |
|
|
226
|
+
| 6 | Wire Drawer to View_Environment | C | First control upgrade, validates the pattern |
|
|
227
|
+
| 7 | Refactor showcase to use compose_adaptive | E | Reference implementation |
|
|
228
|
+
|
|
229
|
+
## What Not to Build
|
|
230
|
+
|
|
231
|
+
Some things are explicitly **out of scope** for the near-term, either because they're premature or because simpler alternatives exist:
|
|
232
|
+
|
|
233
|
+
- **Automatic container-query composition** — useful later, but viewport-level adaptation covers 90% of cases. Ship viewport first.
|
|
234
|
+
- **Visual regression pixel comparison** — screenshot captures for human review are sufficient. Pixel-diff tools add complexity with marginal value at this scale.
|
|
235
|
+
- **Server-side device detection** — User-Agent parsing is unreliable and shrinking in value. Desktop-first SSR with client refinement is simpler and more robust.
|
|
236
|
+
- **per-control CSS-only responsive overrides** — mode attributes and token tiers handle this at scale. Per-control media queries should be the exception, not the pattern.
|
|
237
|
+
|
|
238
|
+
## Strategic Summary
|
|
239
|
+
|
|
240
|
+
The adaptive composition system is not a big-bang rewrite. It's a thin coordination layer on top of strong existing foundations:
|
|
241
|
+
|
|
242
|
+
- **Tokens** already handle theming → extend to density
|
|
243
|
+
- **MVVM** already separates models → use view.data.model for environment state
|
|
244
|
+
- **Drawer** already has breakpoints → generalize the pattern
|
|
245
|
+
- **Playwright** already tests interactivity → add viewport loops
|
|
246
|
+
- **Showcase** already demonstrates controls → make it responsive
|
|
247
|
+
|
|
248
|
+
Each phase delivers value independently. An app can use Phase A (manual mode attributes in CSS) without Phase B (automatic environment service). Phase C controls gracefully degrade when the environment service isn't present.
|
|
249
|
+
|
|
250
|
+
The goal is that within a few iterations, building a responsive jsgui3 app is **easier than building a non-responsive one**, because the platform defaults to adaptive behavior.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Device-Adaptive Composition & Styling in jsgui3
|
|
2
|
+
|
|
3
|
+
A practical guide to building UIs that work well on every screen — from phones in portrait to widescreen desktops — using the jsgui3 platform's compositional architecture.
|
|
4
|
+
|
|
5
|
+
## Why This Book Exists
|
|
6
|
+
|
|
7
|
+
Modern web applications are expected to work on a phone held one-handed, a tablet propped on a desk, a laptop with a resized browser window, and a 4K monitor. Most frameworks address this with CSS media queries alone, leaving developers to scatter breakpoint logic across dozens of stylesheets with no architectural guidance.
|
|
8
|
+
|
|
9
|
+
jsgui3 has a unique advantage: controls are **composed programmatically** on the server and **activated** on the client. That means the platform can make structural composition decisions — not just styling tweaks — based on screen environment. A sidebar can become a drawer. A multi-column layout can collapse to tabs. A data table can transform into a card list. These are composition changes, not CSS hacks.
|
|
10
|
+
|
|
11
|
+
This book explains how to make those decisions cleanly: where adaptive logic should live, how it interacts with the MVVM model separation that jsgui3 already provides, and what platform infrastructure is needed to make high-level app code stay simple while supporting every device well.
|
|
12
|
+
|
|
13
|
+
## What You'll Learn
|
|
14
|
+
|
|
15
|
+
- What responsive infrastructure jsgui3 already has and where the gaps are
|
|
16
|
+
- A layered composition model that separates business logic from device adaptation
|
|
17
|
+
- How to keep adaptive state in view models without polluting domain data
|
|
18
|
+
- A breakpoint and theming strategy built on the existing token system
|
|
19
|
+
- Concrete assessment of how the showcase app behaves across devices
|
|
20
|
+
- Implementation patterns and APIs for adaptive composition
|
|
21
|
+
- How to test responsive behavior systematically with Playwright
|
|
22
|
+
- A phased roadmap for adopting these patterns across the control catalog
|
|
23
|
+
|
|
24
|
+
## Audience
|
|
25
|
+
|
|
26
|
+
- **Platform maintainers** designing control APIs and infrastructure
|
|
27
|
+
- **App developers** building product UIs on jsgui3
|
|
28
|
+
- **Contributors** implementing responsive, theme, and accessibility features
|
|
29
|
+
|
|
30
|
+
## Reading Order
|
|
31
|
+
|
|
32
|
+
The chapters build on each other. Chapters 1–3 establish concepts. Chapters 4–5 apply them concretely. Chapters 6–8 provide implementation guidance.
|
|
33
|
+
|
|
34
|
+
1. [Platform Feature Audit](01-platform-feature-audit.md) — what exists today, what's missing
|
|
35
|
+
2. [Responsive Composition Model](02-responsive-composition-model.md) — the four-layer architecture
|
|
36
|
+
3. [Data Model vs View Model](03-data-model-vs-view-model.md) — where adaptive state belongs
|
|
37
|
+
4. [Styling, Themes, and Breakpoints](04-styling-theme-breakpoints.md) — tokens, density, and mode classes
|
|
38
|
+
5. [Showcase App Multi-Device Assessment](05-showcase-app-multi-device-assessment.md) — practical analysis
|
|
39
|
+
6. [Implementation Patterns and APIs](06-implementation-patterns-and-apis.md) — code-level guidance
|
|
40
|
+
7. [Testing Harness and Quality Gates](07-testing-harness-and-quality-gates.md) — viewport-matrix testing
|
|
41
|
+
8. [Roadmap and Adoption Plan](08-roadmap-and-adoption-plan.md) — phased rollout
|
|
42
|
+
|
|
43
|
+
## Core Thesis
|
|
44
|
+
|
|
45
|
+
jsgui3 already has strong primitives for compositional controls, design tokens, and MVVM-style model separation. The next step is to formalize adaptive layout and styling decisions as **first-class platform concepts** so that app developers can express adaptive intent in a few lines of declarative code, while the platform's mid-level and low-level layers handle the complexity of resolution, rendering, and testing.
|
|
46
|
+
|
|
47
|
+
Keep high-level code easy. Let mid-level code absorb complexity. Trust the low-level foundations in lang-tools and html-core to handle the heavy lifting.
|