jsgui3-server 0.0.144 → 0.0.146
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/docs/jsgui3-html-improvement-ideas.md +162 -0
- package/docs/jsgui3-html-improvement-ideas.svg +151 -0
- package/docs/jsgui3-sass-patterns-book/01-vision-and-goals.md +31 -0
- package/docs/jsgui3-sass-patterns-book/02-stack-map.md +40 -0
- package/docs/jsgui3-sass-patterns-book/03-control-local-sass.md +60 -0
- package/docs/jsgui3-sass-patterns-book/04-extension-and-variants.md +76 -0
- package/docs/jsgui3-sass-patterns-book/05-theming-and-tokens.md +54 -0
- package/docs/jsgui3-sass-patterns-book/06-workspace-overrides.md +45 -0
- package/docs/jsgui3-sass-patterns-book/07-resource-and-bundling.md +46 -0
- package/docs/jsgui3-sass-patterns-book/08-examples.md +62 -0
- package/docs/jsgui3-sass-patterns-book/09-testing-and-adoption.md +27 -0
- package/docs/jsgui3-sass-patterns-book/README.md +23 -0
- package/docs/troubleshooting.md +44 -4
- package/examples/controls/14) window, canvas/client.js +1 -1
- package/examples/controls/14b) window, canvas (improved renderer)/client.js +1 -1
- package/examples/controls/14d) window, canvas globe/EarthGlobeRenderer.js +19 -14
- package/examples/controls/14d) window, canvas globe/client.js +1 -1
- package/examples/controls/14d) window, canvas globe/pipeline/TransformStage.js +5 -5
- package/examples/controls/14e) window, canvas multithreaded/client.js +1 -1
- package/examples/controls/14f) window, canvas polyglobe/client.js +1 -1
- package/examples/controls/16) window, form container/client.js +254 -0
- package/examples/controls/16) window, form container/server.js +20 -0
- package/examples/controls/17) window, mvvm binding/client.js +530 -0
- package/examples/controls/17) window, mvvm binding/server.js +20 -0
- package/examples/jsgui3-html/01) mvvm-counter/client.js +648 -0
- package/examples/jsgui3-html/01) mvvm-counter/server.js +21 -0
- package/examples/jsgui3-html/02) date-transform/client.js +764 -0
- package/examples/jsgui3-html/02) date-transform/server.js +21 -0
- package/examples/jsgui3-html/03) form-validation/client.js +1045 -0
- package/examples/jsgui3-html/03) form-validation/server.js +21 -0
- package/examples/jsgui3-html/04) data-grid/client.js +738 -0
- package/examples/jsgui3-html/04) data-grid/server.js +21 -0
- package/examples/jsgui3-html/05) master-detail/client.js +649 -0
- package/examples/jsgui3-html/05) master-detail/server.js +21 -0
- package/examples/jsgui3-html/06) theming/client.js +514 -0
- package/examples/jsgui3-html/06) theming/server.js +21 -0
- package/examples/jsgui3-html/07) mixins/client.js +465 -0
- package/examples/jsgui3-html/07) mixins/server.js +21 -0
- package/examples/jsgui3-html/08) router/client.js +372 -0
- package/examples/jsgui3-html/08) router/server.js +21 -0
- package/examples/jsgui3-html/09) resource-transform/client.js +692 -0
- package/examples/jsgui3-html/09) resource-transform/server.js +21 -0
- package/examples/jsgui3-html/10) binding-debugger/client.js +810 -0
- package/examples/jsgui3-html/10) binding-debugger/server.js +21 -0
- package/examples/jsgui3-html/README.md +48 -0
- package/http/responders/static/Static_Route_HTTP_Responder.js +25 -20
- package/package.json +3 -3
- package/publishers/http-webpageorsite-publisher.js +3 -1
- package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +87 -100
- package/resources/processors/bundlers/js/esbuild/Core_JS_Single_File_Minifying_Bundler_Using_ESBuild.js +89 -60
- package/serve-factory.js +12 -5
- package/server.js +103 -85
- package/tests/README.md +52 -9
- package/tests/bundlers.test.js +53 -47
- package/tests/end-to-end.test.js +336 -365
- package/tests/examples-controls.e2e.test.js +15 -1
- package/tests/fixtures/end-to-end-client.js +54 -0
- package/tests/fixtures/jsgui3-html/binding_debugger_expectations.json +15 -0
- package/tests/fixtures/jsgui3-html/counter_expectations.json +31 -0
- package/tests/fixtures/jsgui3-html/data_grid_expectations.json +26 -0
- package/tests/fixtures/jsgui3-html/date_transform_expectations.json +26 -0
- package/tests/fixtures/jsgui3-html/form_validation_expectations.json +27 -0
- package/tests/fixtures/jsgui3-html/master_detail_expectations.json +15 -0
- package/tests/fixtures/jsgui3-html/mixins_expectations.json +10 -0
- package/tests/fixtures/jsgui3-html/resource_transform_expectations.json +11 -0
- package/tests/fixtures/jsgui3-html/router_expectations.json +10 -0
- package/tests/fixtures/jsgui3-html/theming_expectations.json +10 -0
- package/tests/jsgui3-html-examples.puppeteer.test.js +537 -0
- package/tests/sass-controls.e2e.test.js +123 -9
- package/tests/test-runner.js +1 -0
- package/tests/window-examples.puppeteer.test.js +217 -1
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Small examples
|
|
2
|
+
|
|
3
|
+
These examples are minimal and focus on how Sass can be placed near controls, extended, and overridden per server.
|
|
4
|
+
|
|
5
|
+
## Example 1: control-local Sass
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
class Toast_Notice extends Control {
|
|
9
|
+
constructor(spec = {}) {
|
|
10
|
+
spec.__type_name = spec.__type_name || 'toast_notice';
|
|
11
|
+
super(spec);
|
|
12
|
+
this.add_class('toast-notice');
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
Toast_Notice.scss = `
|
|
17
|
+
.toast-notice {
|
|
18
|
+
background: var(--theme-surface, #1f1f1f);
|
|
19
|
+
color: var(--theme-on-surface, #ffffff);
|
|
20
|
+
padding: 8px 12px;
|
|
21
|
+
}
|
|
22
|
+
`;
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Example 2: extending a control with new Sass
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
class Window_Compact extends Window {
|
|
29
|
+
constructor(spec = {}) {
|
|
30
|
+
spec.__type_name = spec.__type_name || 'window_compact';
|
|
31
|
+
super(spec);
|
|
32
|
+
this.add_class('window-compact');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
Window_Compact.scss = `
|
|
37
|
+
.window-compact .title-bar {
|
|
38
|
+
font-size: 0.85em;
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Example 3: workspace override via server config
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
Server.serve({
|
|
47
|
+
Ctrl: Demo_UI,
|
|
48
|
+
style: {
|
|
49
|
+
load_paths: ['styles/themes'],
|
|
50
|
+
scss_sources: [
|
|
51
|
+
"@use 'obsidian_theme' as *;",
|
|
52
|
+
":root { --theme-surface: $obsidian_surface; }"
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Where to implement
|
|
59
|
+
|
|
60
|
+
- Control-local Sass: `jsgui3-html` control files or app-specific controls.
|
|
61
|
+
- Workspace overrides: `jsgui3-server` configuration for the host app.
|
|
62
|
+
- Theme tokens: a theme package consumed via `load_paths`.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Testing and adoption plan
|
|
2
|
+
|
|
3
|
+
This chapter proposes how to validate Sass behavior and phase it into new workspaces.
|
|
4
|
+
|
|
5
|
+
## Testing suggestions
|
|
6
|
+
|
|
7
|
+
- Add control-level Sass tests to confirm extraction order and compilation.
|
|
8
|
+
- Add theme override tests that validate token overrides in bundled CSS.
|
|
9
|
+
- Add sourcemap tests when a single compilation pass is used.
|
|
10
|
+
|
|
11
|
+
Relevant test locations:
|
|
12
|
+
|
|
13
|
+
- `tests/sass-controls.e2e.test.js`
|
|
14
|
+
- `tests/bundlers.test.js`
|
|
15
|
+
|
|
16
|
+
## Incremental adoption plan
|
|
17
|
+
|
|
18
|
+
1. Define token vocabulary in `jsgui3-html` control CSS.
|
|
19
|
+
2. Introduce a theme package with token overrides.
|
|
20
|
+
3. Add server-level `scss_sources` for the theme in examples.
|
|
21
|
+
4. Expand theme package usage in additional workspaces.
|
|
22
|
+
|
|
23
|
+
## Where to implement
|
|
24
|
+
|
|
25
|
+
- Test coverage: `jsgui3-server/tests`.
|
|
26
|
+
- Token vocabulary: `jsgui3-html` controls and docs.
|
|
27
|
+
- Theme package: new repo, consumed via `style.load_paths`.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# JSGUI3 Sass Patterns Book
|
|
2
|
+
|
|
3
|
+
This book is a set of proposals for how Sass and CSS can be used across the JSGUI3 stack. It focuses on co-locating styles with controls, supporting project-wide theming, and allowing workspace-level overrides without losing default styles.
|
|
4
|
+
|
|
5
|
+
The intent is to document patterns and where they could be implemented, not to prescribe a single build system. Each chapter includes a short "Where to implement" section that points at the relevant layer.
|
|
6
|
+
|
|
7
|
+
## Table of contents
|
|
8
|
+
|
|
9
|
+
1. Vision and goals - `01-vision-and-goals.md`
|
|
10
|
+
2. Stack map - `02-stack-map.md`
|
|
11
|
+
3. Control-local Sass patterns - `03-control-local-sass.md`
|
|
12
|
+
4. Extending controls and variants - `04-extension-and-variants.md`
|
|
13
|
+
5. Theme tokens and runtime theming - `05-theming-and-tokens.md`
|
|
14
|
+
6. Workspace overrides and shared themes - `06-workspace-overrides.md`
|
|
15
|
+
7. Resource pipeline and bundling - `07-resource-and-bundling.md`
|
|
16
|
+
8. Small examples - `08-examples.md`
|
|
17
|
+
9. Testing and adoption plan - `09-testing-and-adoption.md`
|
|
18
|
+
|
|
19
|
+
## Scope notes
|
|
20
|
+
|
|
21
|
+
- These are implementation suggestions that build on existing JSGUI3 behavior.
|
|
22
|
+
- The Sass compiler is already in use in the server pipeline, so patterns lean on that capability.
|
|
23
|
+
- Examples are minimal and designed to be adapted into other workspaces.
|
package/docs/troubleshooting.md
CHANGED
|
@@ -743,8 +743,48 @@ controls.MinimalControl = MinimalControl;
|
|
|
743
743
|
module.exports = jsgui;
|
|
744
744
|
```
|
|
745
745
|
|
|
746
|
-
This minimal setup helps isolate whether the issue is with your specific code or the framework itself.
|
|
747
|
-
|
|
748
|
-
---
|
|
749
|
-
|
|
746
|
+
This minimal setup helps isolate whether the issue is with your specific code or the framework itself.
|
|
747
|
+
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
## Bundling and Test Failures
|
|
751
|
+
|
|
752
|
+
### `waiting for wp_publisher ready` or Publisher Ready Timeout
|
|
753
|
+
|
|
754
|
+
**Symptoms:**
|
|
755
|
+
- Tests hang while starting servers
|
|
756
|
+
- Logs show `waiting for wp_publisher ready`
|
|
757
|
+
- Tests time out without a clear stack trace
|
|
758
|
+
|
|
759
|
+
**Likely cause:** the JS/CSS bundler failed before emitting `ready`.
|
|
760
|
+
|
|
761
|
+
**What to check:**
|
|
762
|
+
1. Look earlier in the log for bundler errors (esbuild, Sass, file resolution).
|
|
763
|
+
2. Confirm `sass` is installed if you are running Sass tests.
|
|
764
|
+
3. Validate the client entry path passed to `src_path_client_js`.
|
|
765
|
+
|
|
766
|
+
### esbuild platform mismatch (Windows vs WSL)
|
|
767
|
+
|
|
768
|
+
**Symptoms:**
|
|
769
|
+
- Error: `You installed esbuild for another platform than the one you're currently using`
|
|
770
|
+
|
|
771
|
+
**Cause:** `node_modules` was installed on a different OS and reused in this environment.
|
|
772
|
+
|
|
773
|
+
**Fix:**
|
|
774
|
+
1. Remove the existing `node_modules` from the current workspace.
|
|
775
|
+
2. Reinstall dependencies in the current environment:
|
|
776
|
+
```bash
|
|
777
|
+
npm install
|
|
778
|
+
```
|
|
779
|
+
3. If you prefer to keep the lockfile untouched, use:
|
|
780
|
+
```bash
|
|
781
|
+
npm ci
|
|
782
|
+
```
|
|
783
|
+
4. As a fast workaround, you can try:
|
|
784
|
+
```bash
|
|
785
|
+
npm rebuild esbuild
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
---
|
|
789
|
+
|
|
750
790
|
Remember: Most issues can be resolved by carefully checking the console output, verifying file paths, and ensuring proper control lifecycle management. Start with the basics and work systematically through the possible causes.
|
|
@@ -149,19 +149,24 @@ class EarthGlobeRenderer {
|
|
|
149
149
|
enablePipeline() { this.pipelineEnabled = true; }
|
|
150
150
|
disablePipeline() { this.pipelineEnabled = false; }
|
|
151
151
|
setSunDirection(vec3) { this.sun = this._normVec(vec3); this.render(false); }
|
|
152
|
-
setSunFromSpherical(lonDeg, latDeg) {
|
|
153
|
-
// convenience API used by existing client code
|
|
154
|
-
const λ = lonDeg * Math.PI/180;
|
|
155
|
-
const φ = latDeg * Math.PI/180;
|
|
156
|
-
const cφ = Math.cos(φ);
|
|
157
|
-
this.setSunDirection([
|
|
158
|
-
cφ * Math.sin(λ),
|
|
159
|
-
Math.sin(φ),
|
|
160
|
-
cφ * Math.cos(λ)
|
|
161
|
-
]);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
152
|
+
setSunFromSpherical(lonDeg, latDeg) {
|
|
153
|
+
// convenience API used by existing client code
|
|
154
|
+
const λ = lonDeg * Math.PI/180;
|
|
155
|
+
const φ = latDeg * Math.PI/180;
|
|
156
|
+
const cφ = Math.cos(φ);
|
|
157
|
+
this.setSunDirection([
|
|
158
|
+
cφ * Math.sin(λ),
|
|
159
|
+
Math.sin(φ),
|
|
160
|
+
cφ * Math.cos(λ)
|
|
161
|
+
]);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
_update_rot() {
|
|
165
|
+
this.R = mat3FromQuat(this.q);
|
|
166
|
+
this.Rt = mat3Transpose(this.R);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
_buildContinents() {
|
|
165
170
|
const arr = [];
|
|
166
171
|
for (const name of Object.keys(CONTINENT_OUTLINES)) {
|
|
167
172
|
const def = CONTINENT_OUTLINES[name];
|
|
@@ -356,4 +361,4 @@ class EarthGlobeRenderer {
|
|
|
356
361
|
}
|
|
357
362
|
}
|
|
358
363
|
|
|
359
|
-
module.exports = EarthGlobeRenderer;
|
|
364
|
+
module.exports = EarthGlobeRenderer;
|
|
@@ -2,9 +2,9 @@ const BaseStage = require('./BaseStage');
|
|
|
2
2
|
|
|
3
3
|
class TransformStage extends BaseStage {
|
|
4
4
|
/** @param {RenderState} rs */
|
|
5
|
-
execute(rs) {
|
|
6
|
-
const r = this.r;
|
|
7
|
-
r.
|
|
5
|
+
execute(rs) {
|
|
6
|
+
const r = this.r;
|
|
7
|
+
r._update_rot();
|
|
8
8
|
|
|
9
9
|
const rect = r.canvas.getBoundingClientRect();
|
|
10
10
|
const width = rect.width || r.canvas.width / r.opts.dpr;
|
|
@@ -13,8 +13,8 @@ class TransformStage extends BaseStage {
|
|
|
13
13
|
rs.height = height;
|
|
14
14
|
|
|
15
15
|
const pad = r.opts.padding;
|
|
16
|
-
const
|
|
17
|
-
rs.radius = Math.max(1,
|
|
16
|
+
const min_side = Math.min(width, height);
|
|
17
|
+
rs.radius = Math.max(1, min_side / 2 - pad);
|
|
18
18
|
rs.cx = width * 0.5;
|
|
19
19
|
rs.cy = height * 0.5;
|
|
20
20
|
}
|
|
@@ -515,7 +515,7 @@ class Demo_UI extends Active_HTML_Document {
|
|
|
515
515
|
});
|
|
516
516
|
windowCtrl.size = [1000, 1000];
|
|
517
517
|
|
|
518
|
-
const canvas = new controls.
|
|
518
|
+
const canvas = new controls.Canvas({ context });
|
|
519
519
|
canvas.dom.attributes.id = 'globeCanvas';
|
|
520
520
|
canvas.size = [900, 900];
|
|
521
521
|
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
const jsgui = require('jsgui3-client');
|
|
2
|
+
const { controls, Control } = jsgui;
|
|
3
|
+
|
|
4
|
+
const Active_HTML_Document = require('../../../controls/Active_HTML_Document');
|
|
5
|
+
|
|
6
|
+
const { Alert_Banner, Button, Form_Container, Window } = controls;
|
|
7
|
+
|
|
8
|
+
const validate_email = value => {
|
|
9
|
+
const trimmed = String(value || '').trim();
|
|
10
|
+
if (!trimmed) return 'Email is required.';
|
|
11
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmed)) return 'Enter a valid email.';
|
|
12
|
+
return true;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const validate_age = value => {
|
|
16
|
+
if (value === '' || value === undefined || value === null) return true;
|
|
17
|
+
const numeric = Number(value);
|
|
18
|
+
if (!Number.isFinite(numeric)) return 'Enter a number.';
|
|
19
|
+
if (numeric < 16 || numeric > 120) return 'Age must be between 16 and 120.';
|
|
20
|
+
return true;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const validate_bio = value => {
|
|
24
|
+
const trimmed = String(value || '').trim();
|
|
25
|
+
if (trimmed.length < 20) return 'Share at least 20 characters.';
|
|
26
|
+
return true;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
class Demo_UI extends Active_HTML_Document {
|
|
30
|
+
constructor(spec = {}) {
|
|
31
|
+
spec.__type_name = spec.__type_name || 'demo_ui';
|
|
32
|
+
super(spec);
|
|
33
|
+
const { context } = this;
|
|
34
|
+
|
|
35
|
+
if (typeof this.body.add_class === 'function') {
|
|
36
|
+
this.body.add_class('demo-ui');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const compose_ui = () => {
|
|
40
|
+
const window_ctrl = new Window({
|
|
41
|
+
context,
|
|
42
|
+
title: 'jsgui3-html Form_Container',
|
|
43
|
+
pos: [10, 10]
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
window_ctrl.size = [640, 520];
|
|
47
|
+
|
|
48
|
+
const alert_banner = new Alert_Banner({
|
|
49
|
+
context,
|
|
50
|
+
status: 'info',
|
|
51
|
+
message: 'Fill out the form and submit to see validation.'
|
|
52
|
+
});
|
|
53
|
+
alert_banner.add_class('form-banner');
|
|
54
|
+
|
|
55
|
+
const fields = [
|
|
56
|
+
{
|
|
57
|
+
name: 'full_name',
|
|
58
|
+
label: 'Full name',
|
|
59
|
+
required: true,
|
|
60
|
+
placeholder: 'Ada Lovelace'
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'email',
|
|
64
|
+
label: 'Email',
|
|
65
|
+
type: 'email',
|
|
66
|
+
required: true,
|
|
67
|
+
placeholder: 'ada@example.com',
|
|
68
|
+
validator: validate_email
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'age',
|
|
72
|
+
label: 'Age',
|
|
73
|
+
type: 'number',
|
|
74
|
+
placeholder: '36',
|
|
75
|
+
validator: validate_age
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'newsletter',
|
|
79
|
+
label: 'Newsletter',
|
|
80
|
+
type: 'checkbox',
|
|
81
|
+
value: true
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: 'bio',
|
|
85
|
+
label: 'Short bio',
|
|
86
|
+
type: 'textarea',
|
|
87
|
+
required: true,
|
|
88
|
+
placeholder: 'What are you working on?',
|
|
89
|
+
validator: validate_bio
|
|
90
|
+
}
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
const form_container = new Form_Container({
|
|
94
|
+
context,
|
|
95
|
+
fields,
|
|
96
|
+
show_status_badge: true
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const actions_row = new Control({
|
|
100
|
+
context,
|
|
101
|
+
tag_name: 'div'
|
|
102
|
+
});
|
|
103
|
+
actions_row.add_class('form-actions');
|
|
104
|
+
|
|
105
|
+
const submit_button = new Button({
|
|
106
|
+
context,
|
|
107
|
+
text: 'Submit'
|
|
108
|
+
});
|
|
109
|
+
submit_button.dom.attributes.type = 'submit';
|
|
110
|
+
submit_button.add_class('button-primary');
|
|
111
|
+
|
|
112
|
+
const reset_button = new Button({
|
|
113
|
+
context,
|
|
114
|
+
text: 'Reset'
|
|
115
|
+
});
|
|
116
|
+
reset_button.dom.attributes.type = 'button';
|
|
117
|
+
reset_button.add_class('button-secondary');
|
|
118
|
+
|
|
119
|
+
actions_row.add(submit_button);
|
|
120
|
+
actions_row.add(reset_button);
|
|
121
|
+
|
|
122
|
+
form_container.add(actions_row);
|
|
123
|
+
|
|
124
|
+
window_ctrl.inner.add(alert_banner);
|
|
125
|
+
window_ctrl.inner.add(form_container);
|
|
126
|
+
|
|
127
|
+
this.body.add(window_ctrl);
|
|
128
|
+
|
|
129
|
+
this.alert_banner = alert_banner;
|
|
130
|
+
this.form_container = form_container;
|
|
131
|
+
this.reset_button = reset_button;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
if (!spec.el) {
|
|
135
|
+
compose_ui();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
activate() {
|
|
140
|
+
if (!this.__active) {
|
|
141
|
+
super.activate();
|
|
142
|
+
|
|
143
|
+
const { form_container, alert_banner, reset_button } = this;
|
|
144
|
+
|
|
145
|
+
if (form_container && alert_banner) {
|
|
146
|
+
form_container.on('submit', e_submit => {
|
|
147
|
+
const values = e_submit && e_submit.values ? e_submit.values : {};
|
|
148
|
+
const summary_name = values.full_name ? `Thanks, ${values.full_name}.` : 'Thanks!';
|
|
149
|
+
alert_banner.set_status('success');
|
|
150
|
+
alert_banner.set_message(`${summary_name} Form submission looks good.`);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
form_container.on('invalid', () => {
|
|
154
|
+
alert_banner.set_status('error');
|
|
155
|
+
alert_banner.set_message('Please fix the highlighted fields and try again.');
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (reset_button && form_container && alert_banner) {
|
|
160
|
+
reset_button.on('click', () => {
|
|
161
|
+
form_container.set_values({
|
|
162
|
+
full_name: '',
|
|
163
|
+
email: '',
|
|
164
|
+
age: '',
|
|
165
|
+
newsletter: false,
|
|
166
|
+
bio: ''
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
if (form_container.field_controls) {
|
|
170
|
+
Object.keys(form_container.field_controls).forEach(field_name => {
|
|
171
|
+
form_container.update_field_status(
|
|
172
|
+
form_container.field_controls[field_name],
|
|
173
|
+
'',
|
|
174
|
+
''
|
|
175
|
+
);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
alert_banner.set_status('info');
|
|
180
|
+
alert_banner.set_message('Form reset.');
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
Demo_UI.css = `
|
|
188
|
+
* {
|
|
189
|
+
margin: 0;
|
|
190
|
+
padding: 0;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
body {
|
|
194
|
+
overflow-x: hidden;
|
|
195
|
+
overflow-y: hidden;
|
|
196
|
+
background-color: #e0e0e0;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.demo-ui .window .inner {
|
|
200
|
+
padding: 16px;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.demo-ui .form-banner {
|
|
204
|
+
margin-bottom: 12px;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.demo-ui .form-actions {
|
|
208
|
+
display: flex;
|
|
209
|
+
justify-content: flex-end;
|
|
210
|
+
gap: 12px;
|
|
211
|
+
padding-top: 8px;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.demo-ui .button-primary {
|
|
215
|
+
border: none;
|
|
216
|
+
border-radius: 4px;
|
|
217
|
+
padding: 6px 14px;
|
|
218
|
+
background: #0d47a1;
|
|
219
|
+
color: #fff;
|
|
220
|
+
cursor: pointer;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.demo-ui .button-secondary {
|
|
224
|
+
border: 1px solid #c5c5c5;
|
|
225
|
+
border-radius: 4px;
|
|
226
|
+
padding: 6px 14px;
|
|
227
|
+
background: #fff;
|
|
228
|
+
color: #333;
|
|
229
|
+
cursor: pointer;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
@media (max-width: 720px) {
|
|
233
|
+
.demo-ui .window .inner {
|
|
234
|
+
padding: 12px;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.demo-ui .form-container-field {
|
|
238
|
+
grid-template-columns: 1fr;
|
|
239
|
+
gap: 6px;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.demo-ui .form-container-message {
|
|
243
|
+
grid-column: 1;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.demo-ui .form-actions {
|
|
247
|
+
flex-direction: column;
|
|
248
|
+
align-items: stretch;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
`;
|
|
252
|
+
|
|
253
|
+
controls.Demo_UI = Demo_UI;
|
|
254
|
+
module.exports = jsgui;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const jsgui = require('./client');
|
|
2
|
+
|
|
3
|
+
const { Demo_UI } = jsgui.controls;
|
|
4
|
+
const Server = require('../../../server');
|
|
5
|
+
|
|
6
|
+
if (require.main === module) {
|
|
7
|
+
const server = new Server({
|
|
8
|
+
Ctrl: Demo_UI,
|
|
9
|
+
src_path_client_js: require.resolve('./client.js')
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
server.one('ready', () => {
|
|
13
|
+
server.start(52000, err => {
|
|
14
|
+
if (err) {
|
|
15
|
+
throw err;
|
|
16
|
+
}
|
|
17
|
+
console.log('server started');
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
}
|