x4js 2.3.12 → 2.3.14
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/aicli.md +61 -5
- package/aicontext.md +22 -4
- package/cli/build-options.mjs +2 -2
- package/cli/build.mjs +8 -2
- package/cli/config.mjs +46 -3
- package/cli/dev.mjs +22 -11
- package/cli/main.mjs +3 -2
- package/package.json +1 -1
- package/src/components/colorinput/colorinput.module.scss +36 -2
- package/src/components/colorinput/colorinput.ts +202 -32
- package/src/components/colorpicker/colorpicker.module.scss +23 -0
- package/src/components/colorpicker/colorpicker.ts +149 -35
- package/src/components/propgrid/progrid.module.scss +49 -31
- package/src/components/propgrid/propgrid.ts +36 -3
- package/src/core/component.ts +14 -5
- package/src/core/core_tools.ts +1 -1
package/aicli.md
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
```
|
|
6
6
|
x4js create <project> [--template <name>] [--no-install]
|
|
7
7
|
x4js templates
|
|
8
|
-
x4js dev [--config <file>] [--host <host>] [--port <port>] [--http|--https] [--open]
|
|
9
|
-
x4js build [--config <file>] [--debug]
|
|
8
|
+
x4js dev [--config <file>] [--env <file>] [--host <host>] [--port <port>] [--http|--https] [--open]
|
|
9
|
+
x4js build [--config <file>] [--env <file>] [--debug]
|
|
10
10
|
x4js --help | --version
|
|
11
11
|
```
|
|
12
12
|
|
|
@@ -76,6 +76,7 @@ Builds the application, serves the output folder and rebuilds on every change.
|
|
|
76
76
|
| Option | Effect |
|
|
77
77
|
|---|---|
|
|
78
78
|
| `--config <file>` | Config file to use. Default: `x4.config.json`. |
|
|
79
|
+
| `--env <file>` | File of variables for `$NAME` in the config (see below). |
|
|
79
80
|
| `--host <host>` | Address to listen on. Default: `127.0.0.1`. |
|
|
80
81
|
| `--port <port>` | Port to listen on. Default: the first free port from 8000. |
|
|
81
82
|
| `--http`, `--https` | Force the protocol, whatever the config says. |
|
|
@@ -83,7 +84,7 @@ Builds the application, serves the output folder and rebuilds on every change.
|
|
|
83
84
|
|
|
84
85
|
- The page reloads when a source or a copied file changes. A change that only touches CSS is applied without reloading.
|
|
85
86
|
- Build errors and warnings are printed in the terminal.
|
|
86
|
-
- Editing the config file restarts the build.
|
|
87
|
+
- Editing the config file restarts the build. The file given to `--env` is read again at that moment; editing it alone restarts nothing.
|
|
87
88
|
- HTTPS needs a certificate and a key, declared in `dev.tls` (see below).
|
|
88
89
|
|
|
89
90
|
### `x4js build`
|
|
@@ -93,6 +94,7 @@ Writes the application to the output folder.
|
|
|
93
94
|
| Option | Effect |
|
|
94
95
|
|---|---|
|
|
95
96
|
| `--config <file>` | Config file to use. Default: `x4.config.json`. |
|
|
97
|
+
| `--env <file>` | File of variables for `$NAME` in the config (see below). |
|
|
96
98
|
| `--debug` | Debug build: not minified, with source maps. |
|
|
97
99
|
|
|
98
100
|
The output folder is **emptied before each build**. Do not keep hand-written files in it: put them in the sources and list them in `copy`.
|
|
@@ -129,7 +131,60 @@ The file sits at the root of the project. Every key is optional; without the fil
|
|
|
129
131
|
| `dev` | | Dev server settings: `host`, `port`, `https`, `tls`. |
|
|
130
132
|
| `esbuild` | `{}` | Native esbuild options, applied last. They override everything above. |
|
|
131
133
|
|
|
132
|
-
Relative paths are resolved from the project root. Paths accept environment variables, written `$NAME` or `${NAME}`; an undefined variable is an error.
|
|
134
|
+
Relative paths are resolved from the project root. Paths and `define` values accept environment variables, written `$NAME` or `${NAME}`; an undefined variable is an error.
|
|
135
|
+
|
|
136
|
+
### Environment variables in `define`
|
|
137
|
+
|
|
138
|
+
A `define` value is a JavaScript expression, so a text is written between escaped double quotes. The variable is read when the command runs: its value ends up in the bundle.
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"define": {
|
|
143
|
+
"API_URL": "\"$API_URL\"",
|
|
144
|
+
"API_PORT": "$API_PORT"
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
declare const API_URL: string;
|
|
151
|
+
declare const API_PORT: number;
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
With `API_URL=https://example.com` and `API_PORT=8080`, the code sees the text `"https://example.com"` and the number `8080`. A quote or a backslash in the value of a variable is escaped: use double quotes around `$NAME`, not single ones.
|
|
155
|
+
|
|
156
|
+
Everything in the bundle is public: do not put a secret in `define`.
|
|
157
|
+
|
|
158
|
+
### Variables from a file
|
|
159
|
+
|
|
160
|
+
`--env <file>` reads variables from a file of `NAME=value` lines, for `dev` and `build`:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
# .env
|
|
164
|
+
API_URL=https://example.com
|
|
165
|
+
API_PORT=8080
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
x4js dev --env .env
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
- The file only serves `$NAME` in the config. Its variables are not given to the application: pass the ones it needs through `define`.
|
|
173
|
+
- A variable already defined in the environment keeps its value: the file only adds the missing ones.
|
|
174
|
+
- A file that does not exist is an error.
|
|
175
|
+
|
|
176
|
+
This lets the same config work on a machine and on a host that defines the variables itself:
|
|
177
|
+
|
|
178
|
+
```json
|
|
179
|
+
{
|
|
180
|
+
"scripts": {
|
|
181
|
+
"dev": "x4js dev --env .env",
|
|
182
|
+
"build": "x4js build"
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Keep the file out of Git when it holds values that are not public.
|
|
133
188
|
|
|
134
189
|
### The HTML page
|
|
135
190
|
|
|
@@ -189,6 +244,7 @@ declare const VERSION_ID: number;
|
|
|
189
244
|
| A file placed in the output folder disappeared | `x4js build` empties the folder. Move the file to the sources and add it to `copy`. |
|
|
190
245
|
| `Cannot find package 'esbuild'` | The dependencies of the `x4js` copy being run are not installed. Run `npm install` in the project. |
|
|
191
246
|
| `Config file not found` | The file given to `--config` does not exist. Without `--config`, a missing `x4.config.json` is not an error. |
|
|
192
|
-
| `Environment variable '…' is not defined` | A path in the config uses `$NAME` and the variable is not set
|
|
247
|
+
| `Environment variable '…' is not defined` | A path or a `define` value in the config uses `$NAME` and the variable is not set, in the environment or in the file given to `--env`. |
|
|
248
|
+
| `Env file not found` | The file given to `--env` does not exist. |
|
|
193
249
|
| `LESS support requires the "less" package` | A `.less` file is imported and `less` is not installed in the project. |
|
|
194
250
|
| No colors in the terminal, or unwanted ones | Set `FORCE_COLOR=1` to force them, `NO_COLOR=1` to remove them. |
|
package/aicontext.md
CHANGED
|
@@ -130,7 +130,7 @@ interface ComponentProps {
|
|
|
130
130
|
ns?: string // SVG/MathML namespace
|
|
131
131
|
cls?: string // extra CSS classes
|
|
132
132
|
id?: string
|
|
133
|
-
style?:
|
|
133
|
+
style?: StyleProps // numbers get "px" except unitless
|
|
134
134
|
attrs?: Record<string, string | number | boolean>
|
|
135
135
|
content?: ComponentContent
|
|
136
136
|
dom_events?: GlobalDOMEvents
|
|
@@ -188,7 +188,7 @@ getInternalData<T>(name: string|symbol): T
|
|
|
188
188
|
### Styles
|
|
189
189
|
|
|
190
190
|
```ts
|
|
191
|
-
setStyle(style:
|
|
191
|
+
setStyle(style: StyleProps): this // numbers auto-suffixed "px" except unitless
|
|
192
192
|
setStyleValue<K>(name: K, value): this
|
|
193
193
|
getStyleValue<K>(name: K): CSSStyleDeclaration[K]
|
|
194
194
|
setWidth(w: number|string): void
|
|
@@ -633,7 +633,20 @@ class AutoComplete extends TextEdit {
|
|
|
633
633
|
### `ColorInput`
|
|
634
634
|
|
|
635
635
|
```ts
|
|
636
|
-
|
|
636
|
+
interface ColorInputProps extends BoxProps {
|
|
637
|
+
color: Color | string // null: no color shown
|
|
638
|
+
name?: string
|
|
639
|
+
format?: "rgb" | "hex" // text of the field, "rgb" by default
|
|
640
|
+
picker?: boolean // a click on the swatch opens a ColorPicker
|
|
641
|
+
swatches?: (Color|string)[] | (() => (Color|string)[]) // a function is called each time the picker opens
|
|
642
|
+
nullable?: boolean // "no color" can be chosen
|
|
643
|
+
change?: EventCallback<EvColorChange> // user changes only, not setColor
|
|
644
|
+
}
|
|
645
|
+
class ColorInput extends HBox { // queryInterface("form-element"): "#rrggbb" or null
|
|
646
|
+
getColor(): Color; getValue(): string
|
|
647
|
+
setColor(color: Color | string): void; setSwatches(swatches): void
|
|
648
|
+
}
|
|
649
|
+
interface EvColorChange extends EvChange { color: Color; value: string } // "#rrggbb" or "#rrggbbaa"; both null for "no color"
|
|
637
650
|
```
|
|
638
651
|
|
|
639
652
|
### `FileDrop` / `FileDialog`
|
|
@@ -796,6 +809,9 @@ class PropertyGrid extends VBox {
|
|
|
796
809
|
setItems(groups: PropertyGroup[]): void
|
|
797
810
|
setPropValue(name: string, value): void
|
|
798
811
|
}
|
|
812
|
+
// PropertyValue.type: 'boolean' | 'number' | 'string' | 'password' | 'options' | 'color' | 'label' | 'button'
|
|
813
|
+
// 'color': the editor is a ColorInput (hex, with picker); swatches?: string[] | (() => string[]), nullable?: boolean,
|
|
814
|
+
// callback(name, value) receives "#rrggbb", or null for "no color"
|
|
799
815
|
```
|
|
800
816
|
|
|
801
817
|
---
|
|
@@ -978,7 +994,9 @@ class Video extends Box {
|
|
|
978
994
|
set stream(stream: MediaStream)
|
|
979
995
|
}
|
|
980
996
|
class Calendar extends VBox { getDate(): Date; setDate(date: Date): void }
|
|
981
|
-
class ColorPicker extends VBox
|
|
997
|
+
class ColorPicker extends VBox { // props: color, swatches?, nullable?; "change": EvColorChange, also fired once when built
|
|
998
|
+
getColor(): Color; setColor(color: Color | string): void; setSwatches(swatches): void
|
|
999
|
+
}
|
|
982
1000
|
class Panel extends VBox { setTitle(title: string): void }
|
|
983
1001
|
class Breadcrumbs extends HBox { setItems(elements): void }
|
|
984
1002
|
class Keyboard extends HBox // virtual keyboard
|
package/cli/build-options.mjs
CHANGED
|
@@ -27,12 +27,12 @@ export function createBuildOptions(config, mode) {
|
|
|
27
27
|
charset: "utf8",
|
|
28
28
|
keepNames: true,
|
|
29
29
|
platform: "browser",
|
|
30
|
-
|
|
30
|
+
// Errors and warnings are printed by diagnostic-plugin.mjs.
|
|
31
|
+
logLevel: "silent",
|
|
31
32
|
format: "iife",
|
|
32
33
|
target: "es2020",
|
|
33
34
|
minify: production,
|
|
34
35
|
sourcemap: production ? false : "linked",
|
|
35
|
-
logLevel: "info",
|
|
36
36
|
external: config.external,
|
|
37
37
|
assetNames: "assets/[name]-[hash]",
|
|
38
38
|
loader: {
|
package/cli/build.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import { parseArgs } from "node:util";
|
|
3
3
|
import esbuild from "esbuild";
|
|
4
|
-
import { DEFAULT_CONFIG_FILE, expandEnv, loadConfig } from "./config.mjs";
|
|
4
|
+
import { DEFAULT_CONFIG_FILE, expandEnv, loadConfig, loadEnvFile } from "./config.mjs";
|
|
5
5
|
import { createBuildOptions } from "./build-options.mjs";
|
|
6
6
|
import { info, success } from "./log.mjs";
|
|
7
7
|
import { printBuildError, printWarnings } from "./diagnostic-plugin.mjs";
|
|
@@ -11,6 +11,7 @@ export async function build(argv = [], root = process.cwd()) {
|
|
|
11
11
|
args: argv,
|
|
12
12
|
options: {
|
|
13
13
|
config: { type: "string" },
|
|
14
|
+
env: { type: "string" },
|
|
14
15
|
debug: { type: "boolean", default: false },
|
|
15
16
|
},
|
|
16
17
|
allowPositionals: true,
|
|
@@ -20,12 +21,17 @@ export async function build(argv = [], root = process.cwd()) {
|
|
|
20
21
|
if (positionals.length)
|
|
21
22
|
throw new Error(`Unexpected argument: ${positionals[0]}`);
|
|
22
23
|
|
|
24
|
+
const envFile = values.env ? loadEnvFile(root, values.env) : undefined;
|
|
25
|
+
const env = envFile?.env ?? process.env;
|
|
26
|
+
|
|
23
27
|
const configArg = values.config ? expandEnv(values.config) : DEFAULT_CONFIG_FILE;
|
|
24
|
-
const config = loadConfig(root, configArg,
|
|
28
|
+
const config = loadConfig(root, configArg, env, { explicit: values.config !== undefined });
|
|
25
29
|
const mode = values.debug ? "debug" : "production";
|
|
26
30
|
|
|
27
31
|
info("mode", mode);
|
|
28
32
|
info("config", config.configFile);
|
|
33
|
+
if (envFile)
|
|
34
|
+
info("env file", envFile.filename);
|
|
29
35
|
info("outdir", config.outdir);
|
|
30
36
|
|
|
31
37
|
await fs.rm(config.outdir, { recursive: true, force: true });
|
package/cli/config.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { parseEnv } from "node:util";
|
|
3
4
|
|
|
4
5
|
export const DEFAULT_CONFIG_FILE = "x4.config.json";
|
|
5
6
|
|
|
@@ -15,7 +16,7 @@ const DEFAULTS = Object.freeze({
|
|
|
15
16
|
},
|
|
16
17
|
});
|
|
17
18
|
|
|
18
|
-
export function expandEnv(value, env = process.env) {
|
|
19
|
+
export function expandEnv(value, env = process.env, escape = (text) => text) {
|
|
19
20
|
if (typeof value !== "string")
|
|
20
21
|
return value;
|
|
21
22
|
|
|
@@ -26,11 +27,18 @@ export function expandEnv(value, env = process.env) {
|
|
|
26
27
|
const result = env[name];
|
|
27
28
|
if (result === undefined)
|
|
28
29
|
throw new Error(`Environment variable '${name}' is not defined`);
|
|
29
|
-
return result;
|
|
30
|
+
return escape(result);
|
|
30
31
|
},
|
|
31
32
|
);
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
// A define value is a JavaScript expression, usually a string literal
|
|
36
|
+
// ("\"$NAME\""). The value of the variable is escaped so that a quote or a
|
|
37
|
+
// backslash in it cannot end or corrupt that literal.
|
|
38
|
+
function escapeForDefine(text) {
|
|
39
|
+
return JSON.stringify(text).slice(1, -1);
|
|
40
|
+
}
|
|
41
|
+
|
|
34
42
|
export function resolvePath(root, value, env = process.env) {
|
|
35
43
|
const expanded = expandEnv(value, env);
|
|
36
44
|
return path.isAbsolute(expanded)
|
|
@@ -42,6 +50,39 @@ export function resolveConfigFile(root, configFile = DEFAULT_CONFIG_FILE, env =
|
|
|
42
50
|
return resolvePath(root, configFile, env);
|
|
43
51
|
}
|
|
44
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Reads the file given to --env.
|
|
55
|
+
* Returns the environment to expand the config with: the variables of the
|
|
56
|
+
* file, under those already defined, which win as with `node --env-file`.
|
|
57
|
+
*
|
|
58
|
+
* The option is not named --env-file on purpose: node handles that name
|
|
59
|
+
* itself, even after the script name, before this code runs.
|
|
60
|
+
*/
|
|
61
|
+
export function loadEnvFile(root, file, env = process.env) {
|
|
62
|
+
const filename = resolvePath(root, file, env);
|
|
63
|
+
|
|
64
|
+
let variables;
|
|
65
|
+
try {
|
|
66
|
+
variables = parseEnv(fs.readFileSync(filename, "utf8"));
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (error.code === "ENOENT")
|
|
70
|
+
throw new Error(`Env file not found: ${filename}`);
|
|
71
|
+
throw new Error(`Cannot read env file '${filename}': ${error.message}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Inherit from the environment instead of copying it: process.env has
|
|
75
|
+
// its own lookup rules (names are case-insensitive on Windows).
|
|
76
|
+
// defineProperty, because a plain assignment would go through to it.
|
|
77
|
+
const merged = Object.create(env);
|
|
78
|
+
for (const [name, value] of Object.entries(variables)) {
|
|
79
|
+
if (env[name] === undefined)
|
|
80
|
+
Object.defineProperty(merged, name, { value, enumerable: true });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return { filename, env: merged };
|
|
84
|
+
}
|
|
85
|
+
|
|
45
86
|
function readJson(filename) {
|
|
46
87
|
try {
|
|
47
88
|
return JSON.parse(fs.readFileSync(filename, "utf8"));
|
|
@@ -146,7 +187,9 @@ export function loadConfig(root = process.cwd(), configFile = DEFAULT_CONFIG_FIL
|
|
|
146
187
|
to: path.normalize(item.to),
|
|
147
188
|
})),
|
|
148
189
|
external: [...external],
|
|
149
|
-
define:
|
|
190
|
+
define: Object.fromEntries(
|
|
191
|
+
Object.entries(define).map(([name, value]) => [name, expandEnv(value, env, escapeForDefine)]),
|
|
192
|
+
),
|
|
150
193
|
dev: {
|
|
151
194
|
host,
|
|
152
195
|
port,
|
package/cli/dev.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import { parseArgs } from "node:util";
|
|
5
5
|
import esbuild from "esbuild";
|
|
6
|
-
import { DEFAULT_CONFIG_FILE, expandEnv, loadConfig, resolveConfigFile, resolveTls } from "./config.mjs";
|
|
6
|
+
import { DEFAULT_CONFIG_FILE, expandEnv, loadConfig, loadEnvFile, resolveConfigFile, resolveTls } from "./config.mjs";
|
|
7
7
|
import { createBuildOptions } from "./build-options.mjs";
|
|
8
8
|
import { info, success, failure } from "./log.mjs";
|
|
9
9
|
|
|
@@ -60,6 +60,7 @@ export async function dev(argv = [], root = process.cwd()) {
|
|
|
60
60
|
args: argv,
|
|
61
61
|
options: {
|
|
62
62
|
config: { type: "string" },
|
|
63
|
+
env: { type: "string" },
|
|
63
64
|
host: { type: "string" },
|
|
64
65
|
port: { type: "string" },
|
|
65
66
|
http: { type: "boolean", default: false },
|
|
@@ -86,7 +87,16 @@ export async function dev(argv = [], root = process.cwd()) {
|
|
|
86
87
|
let restartChain = Promise.resolve();
|
|
87
88
|
let browserOpened = false;
|
|
88
89
|
|
|
89
|
-
|
|
90
|
+
// Read again on each (re)start, so an edited env file is taken into
|
|
91
|
+
// account when the config is reloaded.
|
|
92
|
+
function load() {
|
|
93
|
+
const envFile = values.env ? loadEnvFile(root, values.env) : undefined;
|
|
94
|
+
const env = envFile?.env ?? process.env;
|
|
95
|
+
const config = loadConfig(root, configArg, env, { explicit: explicitConfig });
|
|
96
|
+
return { config, env, envFile };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function start({ config, env, envFile }) {
|
|
90
100
|
const host = values.host ?? config.dev.host;
|
|
91
101
|
const port = values.port === undefined ? config.dev.port : Number(values.port);
|
|
92
102
|
if (port !== undefined && (port < 0 || port > 65535))
|
|
@@ -101,7 +111,7 @@ export async function dev(argv = [], root = process.cwd()) {
|
|
|
101
111
|
if (port !== undefined)
|
|
102
112
|
serveOptions.port = port;
|
|
103
113
|
if (useHttps)
|
|
104
|
-
Object.assign(serveOptions, resolveTls(config));
|
|
114
|
+
Object.assign(serveOptions, resolveTls(config, env));
|
|
105
115
|
|
|
106
116
|
const next = await esbuild.context(createBuildOptions(config, "dev"));
|
|
107
117
|
try {
|
|
@@ -113,6 +123,8 @@ export async function dev(argv = [], root = process.cwd()) {
|
|
|
113
123
|
const url = serverUrl(actualHost, result.port, useHttps);
|
|
114
124
|
info("mode", "dev");
|
|
115
125
|
info("config", config.configFile);
|
|
126
|
+
if (envFile)
|
|
127
|
+
info("env file", envFile.filename);
|
|
116
128
|
info("outdir", config.outdir);
|
|
117
129
|
success("server", url);
|
|
118
130
|
|
|
@@ -128,12 +140,12 @@ export async function dev(argv = [], root = process.cwd()) {
|
|
|
128
140
|
}
|
|
129
141
|
|
|
130
142
|
async function reload() {
|
|
131
|
-
let
|
|
143
|
+
let loaded;
|
|
132
144
|
try {
|
|
133
|
-
|
|
134
|
-
protocolConfig(config, values);
|
|
135
|
-
if (values.https || (!values.http && config.dev.https))
|
|
136
|
-
resolveTls(config);
|
|
145
|
+
loaded = load();
|
|
146
|
+
protocolConfig(loaded.config, values);
|
|
147
|
+
if (values.https || (!values.http && loaded.config.dev.https))
|
|
148
|
+
resolveTls(loaded.config, loaded.env);
|
|
137
149
|
}
|
|
138
150
|
catch (error) {
|
|
139
151
|
failure(`config: ${error.message}`);
|
|
@@ -146,7 +158,7 @@ export async function dev(argv = [], root = process.cwd()) {
|
|
|
146
158
|
await previous.dispose();
|
|
147
159
|
|
|
148
160
|
try {
|
|
149
|
-
await start(
|
|
161
|
+
await start(loaded);
|
|
150
162
|
success("config", "reloaded");
|
|
151
163
|
}
|
|
152
164
|
catch (error) {
|
|
@@ -161,8 +173,7 @@ export async function dev(argv = [], root = process.cwd()) {
|
|
|
161
173
|
}, 150);
|
|
162
174
|
}
|
|
163
175
|
|
|
164
|
-
|
|
165
|
-
await start(initialConfig);
|
|
176
|
+
await start(load());
|
|
166
177
|
|
|
167
178
|
const watchDir = path.dirname(watchedConfigFile);
|
|
168
179
|
const watchName = path.basename(watchedConfigFile);
|
package/cli/main.mjs
CHANGED
|
@@ -21,11 +21,12 @@ function printHelp(version) {
|
|
|
21
21
|
Usage:
|
|
22
22
|
x4js create <project> [--template <name>] [--no-install]
|
|
23
23
|
x4js templates
|
|
24
|
-
x4js dev [--config <file>] [--host <host>] [--port <port>] [--http|--https] [--open]
|
|
25
|
-
x4js build [--config <file>] [--debug]
|
|
24
|
+
x4js dev [--config <file>] [--env <file>] [--host <host>] [--port <port>] [--http|--https] [--open]
|
|
25
|
+
x4js build [--config <file>] [--env <file>] [--debug]
|
|
26
26
|
|
|
27
27
|
Options:
|
|
28
28
|
--config <file> Config file (default: x4.config.json)
|
|
29
|
+
--env <file> File of NAME=value lines, for $NAME in the config
|
|
29
30
|
-h, --help Show help
|
|
30
31
|
-v, --version Show version`);
|
|
31
32
|
}
|
package/package.json
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
:root {
|
|
18
18
|
--colorinput-btn-background: inherit;
|
|
19
19
|
--colorinput-btn-color: var( --text-secondary );
|
|
20
|
-
--colorinput-btn-color-hover: var( --text-primary );
|
|
20
|
+
--colorinput-btn-color-hover: var( --text-primary );
|
|
21
|
+
--colorinput-popup-background: var( --background-primary );
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
.x4colorinput {
|
|
@@ -33,6 +34,27 @@
|
|
|
33
34
|
margin: 4px;
|
|
34
35
|
width: 1rem;
|
|
35
36
|
height: 1rem;
|
|
37
|
+
|
|
38
|
+
// props.picker: a click opens the color picker. It is a button:
|
|
39
|
+
// wide enough to be aimed at.
|
|
40
|
+
&.picker {
|
|
41
|
+
flex-shrink: 0;
|
|
42
|
+
width: 2.4rem;
|
|
43
|
+
height: 1.4rem;
|
|
44
|
+
border: 1px solid var( --border );
|
|
45
|
+
border-radius: 3px;
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
|
|
48
|
+
&:hover {
|
|
49
|
+
border-color: var( --border-focus );
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// props.nullable, no color: crossed out
|
|
54
|
+
&.none {
|
|
55
|
+
border: 1px solid var( --border );
|
|
56
|
+
background: linear-gradient( to top right, transparent 45%, #d04040 45%, #d04040 55%, transparent 55% );
|
|
57
|
+
}
|
|
36
58
|
}
|
|
37
59
|
|
|
38
60
|
input {
|
|
@@ -42,14 +64,19 @@
|
|
|
42
64
|
flex-grow: 1;
|
|
43
65
|
}
|
|
44
66
|
|
|
67
|
+
// the eye dropper: as high as the field, and wide enough to be aimed at
|
|
45
68
|
.x4button {
|
|
69
|
+
flex-shrink: 0;
|
|
70
|
+
align-self: stretch;
|
|
46
71
|
margin: 0;
|
|
47
|
-
padding: 0;
|
|
72
|
+
padding: 0 6px;
|
|
48
73
|
outline: none;
|
|
49
74
|
background-color: var( --combobox-btn-background );
|
|
50
75
|
color: var( --colorinput-btn-color );
|
|
51
76
|
|
|
52
77
|
#icon {
|
|
78
|
+
width: 1.3em;
|
|
79
|
+
height: 1.3em;
|
|
53
80
|
color: var( --colorinput-btn-color );
|
|
54
81
|
}
|
|
55
82
|
|
|
@@ -62,4 +89,11 @@
|
|
|
62
89
|
//color: var( --color-10 );
|
|
63
90
|
}
|
|
64
91
|
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// the color picker opened from the swatch (props.picker)
|
|
95
|
+
.x4colorinput-popup {
|
|
96
|
+
background-color: var( --colorinput-popup-background );
|
|
97
|
+
border: 1px solid var( --border );
|
|
98
|
+
box-shadow: 0 4px 12px rgba( 0, 0, 0, 0.3 );
|
|
65
99
|
}
|