dithercharts 0.1.4 → 0.1.5
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/README.md +7 -7
- package/dist/cli.js +5 -5
- package/dist/commands/add.js +2 -2
- package/dist/commands/list.js +19 -5
- package/dist/errors.js +1 -1
- package/dist/install.js +1 -1
- package/dist/project.js +31 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# dithercharts
|
|
4
4
|
|
|
5
|
-
The CLI for [DitherCharts](https://dithercharts.com), dithered chart components for React. It copies
|
|
5
|
+
The CLI for [DitherCharts](https://dithercharts.com), dithered chart and form control components for React. It copies their source into your React app, so you own and can edit every line.
|
|
6
6
|
|
|
7
7
|
You need a DitherCharts Pro subscription, Node 20 or later, and a React 19 app with TypeScript. Tailwind and shadcn/ui are optional.
|
|
8
8
|
|
|
@@ -14,13 +14,13 @@ Log in once per machine. Your browser opens to confirm a code.
|
|
|
14
14
|
npx dithercharts login
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Then add charts from your app's folder:
|
|
17
|
+
Then add charts and controls from your app's folder:
|
|
18
18
|
|
|
19
19
|
```sh
|
|
20
|
-
npx dithercharts add area-chart
|
|
20
|
+
npx dithercharts add area-chart select
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
Files land in `src/components/dithercharts/` (or `components/dithercharts/` without a `src` folder), and the CLI installs
|
|
23
|
+
Files land in `src/components/dithercharts/` (or `components/dithercharts/` without a `src` folder), and the CLI installs any npm dependencies with your package manager. Run `npx dithercharts list` for every name.
|
|
24
24
|
|
|
25
25
|
## Commands
|
|
26
26
|
|
|
@@ -29,10 +29,10 @@ Files land in `src/components/dithercharts/` (or `components/dithercharts/` with
|
|
|
29
29
|
| `login` | Sign in through the browser and save a key |
|
|
30
30
|
| `logout` | Revoke this machine's key and forget it |
|
|
31
31
|
| `whoami` | Show the signed-in account and plan |
|
|
32
|
-
| `list` | List the charts and what's installed here |
|
|
33
|
-
| `add <names...>` | Install charts into this project |
|
|
32
|
+
| `list` | List the charts and controls, and what's installed here |
|
|
33
|
+
| `add <names...>` | Install charts and controls into this project |
|
|
34
34
|
|
|
35
|
-
`add` options: `--all`, `--dir <path>`, `--yes`, `--overwrite`, `--no-install`.
|
|
35
|
+
`add` options: `--all`, `--dir <path>`, `--yes`, `--overwrite`, `--no-install`. `--yes` asks nothing, so AI agents should pass it: it takes the default folder and keeps files you changed.
|
|
36
36
|
|
|
37
37
|
In CI, set `DITHERCHARTS_API_KEY` instead of running `login`.
|
|
38
38
|
|
package/dist/cli.js
CHANGED
|
@@ -18,11 +18,11 @@ Commands:
|
|
|
18
18
|
login Sign in through the browser and save a key
|
|
19
19
|
logout Revoke this machine's key and forget it
|
|
20
20
|
whoami Show the signed-in account and plan
|
|
21
|
-
list List the charts and what's installed here
|
|
22
|
-
add <names...> Install charts into this project
|
|
23
|
-
--all Install every chart
|
|
21
|
+
list List the charts and controls, and what's installed here
|
|
22
|
+
add <names...> Install charts and controls into this project
|
|
23
|
+
--all Install every chart and control
|
|
24
24
|
--dir <path> Folder to install into
|
|
25
|
-
--yes, -y
|
|
25
|
+
--yes, -y Ask nothing: use the default folder, keep local changes
|
|
26
26
|
--overwrite Replace files you changed locally
|
|
27
27
|
--no-install Print the dependency install command instead of running it
|
|
28
28
|
|
|
@@ -31,7 +31,7 @@ Environment:
|
|
|
31
31
|
DITHERCHARTS_URL Server to use (default ${DEFAULT_BASE_URL})`;
|
|
32
32
|
const version = () => JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version;
|
|
33
33
|
function welcome() {
|
|
34
|
-
const side = { 4: "Welcome to DitherCharts", 5: `v${version()} · dithered charts for React` };
|
|
34
|
+
const side = { 4: "Welcome to DitherCharts", 5: `v${version()} · dithered charts and controls for React` };
|
|
35
35
|
return LOGO.split("\n").map((line, i) => (side[i] ? `${line.padEnd(20)}${side[i]}` : line)).join("\n");
|
|
36
36
|
}
|
|
37
37
|
function runCommand(cmd, cwd) {
|
package/dist/commands/add.js
CHANGED
|
@@ -32,7 +32,7 @@ export async function add(opts, deps) {
|
|
|
32
32
|
const items = await Promise.all(resolveOrder(index, names).map((name) => deps.api.item(name)));
|
|
33
33
|
const results = await applyFiles(planFiles(join(root, dir), items), {
|
|
34
34
|
overwrite: opts.overwrite,
|
|
35
|
-
ask: deps.interactive ? deps.askOverwrite : null,
|
|
35
|
+
ask: deps.interactive && !opts.yes ? deps.askOverwrite : null,
|
|
36
36
|
});
|
|
37
37
|
for (const r of results) {
|
|
38
38
|
deps.log(`${MARK[r.result]} ${relative(root, r.path)}${r.result === "skipped" ? " (local changes kept; --overwrite replaces)" : ""}`);
|
|
@@ -55,7 +55,7 @@ export async function add(opts, deps) {
|
|
|
55
55
|
deps.log(`$ ${cmd.join(" ")}`);
|
|
56
56
|
deps.run(cmd, root);
|
|
57
57
|
}
|
|
58
|
-
const base = importBase(dir);
|
|
58
|
+
const base = importBase(root, dir);
|
|
59
59
|
deps.log("");
|
|
60
60
|
for (const [owner, sheet] of STYLESHEETS) {
|
|
61
61
|
if (items.some((i) => i.name === owner))
|
package/dist/commands/list.js
CHANGED
|
@@ -3,10 +3,24 @@ export async function list(deps) {
|
|
|
3
3
|
const index = await deps.api.index();
|
|
4
4
|
const root = findProjectRoot(deps.cwd);
|
|
5
5
|
const installed = (root && readConfig(root)?.items) || {};
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
// Items others depend on (engine, core, controls) come along with them, so they're listed apart.
|
|
7
|
+
const shared = new Set(index.items.flatMap((item) => item.registryDependencies));
|
|
8
|
+
const mine = index.items.filter((item) => !shared.has(item.name));
|
|
9
|
+
const isControl = (item) => item.registryDependencies.includes("controls");
|
|
10
|
+
const groups = [
|
|
11
|
+
["Charts", mine.filter((item) => !isControl(item))],
|
|
12
|
+
["Form controls", mine.filter(isControl)],
|
|
13
|
+
["Shared (add installs these for you)", index.items.filter((item) => shared.has(item.name))],
|
|
14
|
+
];
|
|
15
|
+
groups.forEach(([heading, items], i) => {
|
|
16
|
+
if (i > 0)
|
|
17
|
+
deps.log("");
|
|
18
|
+
deps.log(heading);
|
|
19
|
+
for (const item of items) {
|
|
20
|
+
const have = installed[item.name];
|
|
21
|
+
const note = !have ? "" : have === index.version ? ` [installed ${have}]` : ` [installed ${have}, update: ${index.version}]`;
|
|
22
|
+
deps.log(` ${item.name.padEnd(14)} ${item.description}${note}`);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
11
25
|
return 0;
|
|
12
26
|
}
|
package/dist/errors.js
CHANGED
|
@@ -25,6 +25,6 @@ export function messageFor(status, body, base, name) {
|
|
|
25
25
|
if (status === 403)
|
|
26
26
|
return "This key can't install charts. Log in with `npx dithercharts login` to get a personal key.";
|
|
27
27
|
if (status === 404)
|
|
28
|
-
return name ? `No chart named "${name}". Run \`npx dithercharts list\`.` : "Not found on the server.";
|
|
28
|
+
return name ? `No chart or control named "${name}". Run \`npx dithercharts list\`.` : "Not found on the server.";
|
|
29
29
|
return `The server answered ${status}. Nothing was written; try again.`;
|
|
30
30
|
}
|
package/dist/install.js
CHANGED
|
@@ -8,7 +8,7 @@ export function resolveOrder(index, names) {
|
|
|
8
8
|
const visit = (name) => {
|
|
9
9
|
const item = byName.get(name);
|
|
10
10
|
if (!item)
|
|
11
|
-
throw new CliError(`No chart named "${name}". Run \`npx dithercharts list\`.`);
|
|
11
|
+
throw new CliError(`No chart or control named "${name}". Run \`npx dithercharts list\`.`);
|
|
12
12
|
if (order.includes(name))
|
|
13
13
|
return;
|
|
14
14
|
item.registryDependencies.forEach(visit);
|
package/dist/project.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
2
|
+
import { dirname, join, posix } from "node:path";
|
|
3
3
|
export const CONFIG_FILE = "dithercharts.json";
|
|
4
4
|
/** The nearest folder at or above `cwd` with a package.json. */
|
|
5
5
|
export function findProjectRoot(cwd) {
|
|
@@ -46,8 +46,36 @@ export function reactMajor(pkg) {
|
|
|
46
46
|
const major = range?.match(/\d+/)?.[0];
|
|
47
47
|
return major ? Number(major) : null;
|
|
48
48
|
}
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
// tsconfig files allow comments and trailing commas. Strings are matched first and kept, since "@/*" holds "/*".
|
|
50
|
+
const COMMENT = /("(?:\\.|[^"\\])*")|\/\/[^\n]*|\/\*[\s\S]*?\*\//g;
|
|
51
|
+
const TRAILING_COMMA = /("(?:\\.|[^"\\])*")|,(?=\s*[}\]])/g;
|
|
52
|
+
function readTsconfig(path) {
|
|
53
|
+
try {
|
|
54
|
+
const text = readFileSync(path, "utf8").replace(COMMENT, (_, str) => str ?? "").replace(TRAILING_COMMA, (_, str) => str ?? "");
|
|
55
|
+
return JSON.parse(text).compilerOptions;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** How app code imports the folder: through the tsconfig alias that reaches it ("~/" in T3 apps), else `@/`. */
|
|
62
|
+
export function importBase(root, dir) {
|
|
63
|
+
const folder = posix.normalize(dir);
|
|
64
|
+
// Vite apps keep their compiler options in tsconfig.app.json.
|
|
65
|
+
for (const file of ["tsconfig.json", "tsconfig.app.json"]) {
|
|
66
|
+
const options = readTsconfig(join(root, file));
|
|
67
|
+
for (const [alias, [target] = []] of Object.entries(options?.paths ?? {})) {
|
|
68
|
+
if (!alias.endsWith("/*") || (!target?.endsWith("/*") && target !== "*"))
|
|
69
|
+
continue;
|
|
70
|
+
const base = posix.normalize(posix.join(options?.baseUrl ?? ".", target.slice(0, -1))).replace(/\/$/, "");
|
|
71
|
+
if (base === ".")
|
|
72
|
+
return alias.slice(0, -1) + folder;
|
|
73
|
+
if (folder.startsWith(`${base}/`))
|
|
74
|
+
return alias.slice(0, -1) + folder.slice(base.length + 1);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return `@/${folder.replace(/^src\//, "")}`;
|
|
78
|
+
}
|
|
51
79
|
/** "area-chart" → "AreaChart". */
|
|
52
80
|
export const componentName = (item) => item
|
|
53
81
|
.split("-")
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dithercharts",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Install DitherCharts Pro charts into your React app.",
|
|
3
|
+
"version": "0.1.5",
|
|
4
|
+
"description": "Install DitherCharts Pro charts and form controls into your React app.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dithercharts",
|
|
7
7
|
"charts",
|