tempest-react-sdk 0.27.0 → 0.28.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -2
- package/bin/lib/css/analyze.mjs +149 -0
- package/bin/lib/css/analyze.test.mjs +136 -0
- package/bin/lib/css/collect.mjs +152 -0
- package/bin/lib/css/findings.mjs +79 -0
- package/bin/lib/css/fix.e2e.test.mjs +99 -0
- package/bin/lib/css/fix.mjs +138 -0
- package/bin/lib/css/fix.test.mjs +108 -0
- package/bin/lib/css/index.mjs +16 -0
- package/bin/lib/css/parse.mjs +398 -0
- package/bin/lib/css/parse.test.mjs +146 -0
- package/bin/lib/css/properties.mjs +399 -0
- package/bin/lib/css/repetition.mjs +213 -0
- package/bin/lib/css/repetition.test.mjs +166 -0
- package/bin/lib/css/semantic.mjs +327 -0
- package/bin/lib/css/semantic.test.mjs +201 -0
- package/bin/lib/css/tokens.mjs +119 -0
- package/bin/lib/doctor/doctor.e2e.test.mjs +45 -0
- package/bin/tempest.mjs +169 -7
- package/dist/charts/scales.cjs +2 -0
- package/dist/charts/scales.cjs.map +1 -0
- package/dist/charts/scales.js +29 -0
- package/dist/charts/scales.js.map +1 -0
- package/dist/charts.cjs +1 -1
- package/dist/charts.d.ts +91 -0
- package/dist/charts.js +9 -8
- package/dist/components/BottomNavigation/BottomNavigation.module.cjs.map +1 -1
- package/dist/components/BottomNavigation/BottomNavigation.module.js.map +1 -1
- package/dist/components/Carousel/Carousel.module.cjs.map +1 -1
- package/dist/components/Carousel/Carousel.module.js.map +1 -1
- package/dist/components/CodeBlock/CodeBlock.cjs +3 -0
- package/dist/components/CodeBlock/CodeBlock.cjs.map +1 -0
- package/dist/components/CodeBlock/CodeBlock.js +53 -0
- package/dist/components/CodeBlock/CodeBlock.js.map +1 -0
- package/dist/components/CodeBlock/CodeBlock.module.cjs +2 -0
- package/dist/components/CodeBlock/CodeBlock.module.cjs.map +1 -0
- package/dist/components/CodeBlock/CodeBlock.module.js +29 -0
- package/dist/components/CodeBlock/CodeBlock.module.js.map +1 -0
- package/dist/components/CodeBlock/tokenize.cjs +3 -0
- package/dist/components/CodeBlock/tokenize.cjs.map +1 -0
- package/dist/components/CodeBlock/tokenize.js +267 -0
- package/dist/components/CodeBlock/tokenize.js.map +1 -0
- package/dist/components/Navbar/Navbar.module.cjs.map +1 -1
- package/dist/components/Navbar/Navbar.module.js.map +1 -1
- package/dist/components/QRCode/QRCode.cjs +2 -0
- package/dist/components/QRCode/QRCode.cjs.map +1 -0
- package/dist/components/QRCode/QRCode.js +49 -0
- package/dist/components/QRCode/QRCode.js.map +1 -0
- package/dist/components/QRCode/QRCode.module.cjs +2 -0
- package/dist/components/QRCode/QRCode.module.cjs.map +1 -0
- package/dist/components/QRCode/QRCode.module.js +9 -0
- package/dist/components/QRCode/QRCode.module.js.map +1 -0
- package/dist/components/QRCode/qr-encode.cjs +2 -0
- package/dist/components/QRCode/qr-encode.cjs.map +1 -0
- package/dist/components/QRCode/qr-encode.js +295 -0
- package/dist/components/QRCode/qr-encode.js.map +1 -0
- package/dist/components/QRCode/qr-tables.cjs +2 -0
- package/dist/components/QRCode/qr-tables.cjs.map +1 -0
- package/dist/components/QRCode/qr-tables.js +366 -0
- package/dist/components/QRCode/qr-tables.js.map +1 -0
- package/dist/components/ScrollArea/ScrollArea.cjs +1 -1
- package/dist/components/ScrollArea/ScrollArea.cjs.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.js +22 -16
- package/dist/components/ScrollArea/ScrollArea.js.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.module.cjs.map +1 -1
- package/dist/components/ScrollArea/ScrollArea.module.js.map +1 -1
- package/dist/components/Sparkline/Sparkline.cjs +2 -0
- package/dist/components/Sparkline/Sparkline.cjs.map +1 -0
- package/dist/components/Sparkline/Sparkline.js +64 -0
- package/dist/components/Sparkline/Sparkline.js.map +1 -0
- package/dist/components/Sparkline/Sparkline.module.cjs +2 -0
- package/dist/components/Sparkline/Sparkline.module.cjs.map +1 -0
- package/dist/components/Sparkline/Sparkline.module.js +10 -0
- package/dist/components/Sparkline/Sparkline.module.js.map +1 -0
- package/dist/components/Sparkline/sparkline-geometry.cjs +2 -0
- package/dist/components/Sparkline/sparkline-geometry.cjs.map +1 -0
- package/dist/components/Sparkline/sparkline-geometry.js +56 -0
- package/dist/components/Sparkline/sparkline-geometry.js.map +1 -0
- package/dist/components/Table/Table.cjs +1 -1
- package/dist/components/Table/Table.cjs.map +1 -1
- package/dist/components/Table/Table.js +37 -30
- package/dist/components/Table/Table.js.map +1 -1
- package/dist/components/Table/Table.module.cjs.map +1 -1
- package/dist/components/Table/Table.module.js.map +1 -1
- package/dist/components/VirtualList/VirtualList.cjs +1 -1
- package/dist/components/VirtualList/VirtualList.cjs.map +1 -1
- package/dist/components/VirtualList/VirtualList.js +13 -11
- package/dist/components/VirtualList/VirtualList.js.map +1 -1
- package/dist/components/VirtualList/VirtualList.module.cjs.map +1 -1
- package/dist/components/VirtualList/VirtualList.module.js.map +1 -1
- package/dist/hooks/use-scroll-overflow.cjs +2 -0
- package/dist/hooks/use-scroll-overflow.cjs.map +1 -0
- package/dist/hooks/use-scroll-overflow.js +22 -0
- package/dist/hooks/use-scroll-overflow.js.map +1 -0
- package/dist/push/utils.cjs +1 -1
- package/dist/push/utils.cjs.map +1 -1
- package/dist/push/utils.js +1 -1
- package/dist/push/utils.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/tempest-react-sdk.cjs +1 -1
- package/dist/tempest-react-sdk.d.ts +450 -2
- package/dist/tempest-react-sdk.js +197 -190
- package/dist/theme/create-theme.cjs +3 -3
- package/dist/theme/create-theme.cjs.map +1 -1
- package/dist/theme/create-theme.js +52 -28
- package/dist/theme/create-theme.js.map +1 -1
- package/dist/theme/data-viz-ramps.cjs +2 -0
- package/dist/theme/data-viz-ramps.cjs.map +1 -0
- package/dist/theme/data-viz-ramps.js +58 -0
- package/dist/theme/data-viz-ramps.js.map +1 -0
- package/package.json +2 -1
|
@@ -155,6 +155,51 @@ describe("tempest doctor — generic findings still surface", () => {
|
|
|
155
155
|
});
|
|
156
156
|
});
|
|
157
157
|
|
|
158
|
+
describe("tempest doctor — stylesheets", () => {
|
|
159
|
+
beforeEach(thirdPartyApp);
|
|
160
|
+
|
|
161
|
+
it("says nothing about CSS in a project with no stylesheet", () => {
|
|
162
|
+
expect(doctor().out).not.toContain("Stylesheets");
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("reports a clean sheet as clean", () => {
|
|
166
|
+
write("src/app.css", ".a {\n color: red;\n}\n");
|
|
167
|
+
const { out, code } = doctor();
|
|
168
|
+
expect(out).toContain("Stylesheets");
|
|
169
|
+
expect(out).toContain("no CSS problems found");
|
|
170
|
+
expect(code).toBe(0);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("fails the audit on CSS the browser cannot parse", () => {
|
|
174
|
+
write("src/app.css", ".a {\n color: red;\n");
|
|
175
|
+
const { out, code } = doctor();
|
|
176
|
+
expect(out).toContain("src/app.css:1");
|
|
177
|
+
expect(out).toContain("never closed");
|
|
178
|
+
expect(code).toBe(1);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("warns without failing on CSS that is valid but wrong", () => {
|
|
182
|
+
write("src/app.css", ".a {\n bacground-color: red;\n}\n");
|
|
183
|
+
const { out, code } = doctor();
|
|
184
|
+
expect(out).toContain("did you mean `background-color`");
|
|
185
|
+
expect(code).toBe(0);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("points at the fix command when something is auto-fixable", () => {
|
|
189
|
+
write("src/app.css", ".a {\n color: red;\n color: red;\n}\n");
|
|
190
|
+
const { out } = doctor();
|
|
191
|
+
expect(out).toMatch(/finding\(s\) are auto-fixable/);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("suggests one global class over repeated local copies", () => {
|
|
195
|
+
const row = ".row {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n";
|
|
196
|
+
write("src/A.module.css", row);
|
|
197
|
+
write("src/B.module.css", row);
|
|
198
|
+
write("src/C.module.css", row);
|
|
199
|
+
expect(doctor().out).toContain("one global class beats");
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
158
203
|
describe("tempest doctor — a project that does use the SDK", () => {
|
|
159
204
|
beforeEach(() => {
|
|
160
205
|
thirdPartyApp();
|
package/bin/tempest.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import { fileURLToPath } from "node:url";
|
|
|
14
14
|
import { aliasImports } from "./lib/alias/index.mjs";
|
|
15
15
|
import { loadTypeScript } from "./lib/alias/typescript.mjs";
|
|
16
16
|
import { readTsconfig } from "./lib/alias/tsconfig.mjs";
|
|
17
|
+
import { analyzeCss, applyCssFixes } from "./lib/css/index.mjs";
|
|
17
18
|
import { checkLucide } from "./lib/doctor/lucide.mjs";
|
|
18
19
|
import { generateRegistry, loadIconTables } from "./lib/icons/generate.mjs";
|
|
19
20
|
import { generate } from "./lib/openapi/generate.mjs";
|
|
@@ -250,6 +251,74 @@ const STATEFUL_DEPS = [
|
|
|
250
251
|
"react-router-dom",
|
|
251
252
|
];
|
|
252
253
|
|
|
254
|
+
/**
|
|
255
|
+
* Doctor rows for the CSS analysis.
|
|
256
|
+
*
|
|
257
|
+
* Findings are capped per severity because a report nobody reads to the end is a
|
|
258
|
+
* report that hides its own first line. The cap is stated, and the pointer to the
|
|
259
|
+
* uncapped list (`tempest fix --dry-run`) goes with it — a silent truncation
|
|
260
|
+
* would read as "that is all of them".
|
|
261
|
+
*
|
|
262
|
+
* @param {number} [limit] - Findings shown per severity.
|
|
263
|
+
* @returns {Array<[status: string, label: string, detail?: string]>} Check rows.
|
|
264
|
+
*/
|
|
265
|
+
function cssChecks(limit = 6) {
|
|
266
|
+
let analysis;
|
|
267
|
+
try {
|
|
268
|
+
analysis = analyzeCss({ root: ROOT, targets: ["."], selfDir: SELF_DIR });
|
|
269
|
+
} catch (err) {
|
|
270
|
+
return [["warn", "CSS analysis failed", String(err?.message ?? err)]];
|
|
271
|
+
}
|
|
272
|
+
if (analysis.stats.files === 0) return [];
|
|
273
|
+
|
|
274
|
+
const rows = [["section", "Stylesheets"]];
|
|
275
|
+
rows.push([
|
|
276
|
+
"info",
|
|
277
|
+
`${analysis.stats.files} stylesheet(s) · ${analysis.stats.rules} rules · ${analysis.stats.declarations} declarations`,
|
|
278
|
+
analysis.tokens.source ? "" : "SDK token table not found — token checks skipped",
|
|
279
|
+
]);
|
|
280
|
+
if (analysis.truncated) {
|
|
281
|
+
rows.push([
|
|
282
|
+
"info",
|
|
283
|
+
"file cap reached",
|
|
284
|
+
"only the first 600 stylesheets were analyzed — narrow the run with `tempest fix <path> --dry-run`",
|
|
285
|
+
]);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const status = { error: "fail", warn: "warn", info: "info" };
|
|
289
|
+
let hidden = 0;
|
|
290
|
+
for (const severity of ["error", "warn", "info"]) {
|
|
291
|
+
const group = analysis.findings.filter((f) => f.severity === severity);
|
|
292
|
+
for (const f of group.slice(0, limit)) {
|
|
293
|
+
rows.push([status[severity], `${f.file}:${f.line}`, f.message]);
|
|
294
|
+
}
|
|
295
|
+
hidden += Math.max(0, group.length - limit);
|
|
296
|
+
}
|
|
297
|
+
if (hidden > 0) {
|
|
298
|
+
rows.push([
|
|
299
|
+
"info",
|
|
300
|
+
`${hidden} more CSS finding(s) not shown`,
|
|
301
|
+
"run `tempest fix --dry-run` for the full list",
|
|
302
|
+
]);
|
|
303
|
+
}
|
|
304
|
+
if (analysis.findings.length === 0) {
|
|
305
|
+
rows.push(["ok", "no CSS problems found"]);
|
|
306
|
+
} else {
|
|
307
|
+
const fixable = analysis.findings.filter((f) => f.fixable).length;
|
|
308
|
+
if (fixable > 0) {
|
|
309
|
+
rows.push([
|
|
310
|
+
"info",
|
|
311
|
+
`${fixable} finding(s) are auto-fixable`,
|
|
312
|
+
"run `tempest fix` — it removes only what is provably dead",
|
|
313
|
+
]);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
for (const skip of analysis.skipped.slice(0, 3)) {
|
|
317
|
+
rows.push(["info", `skipped ${skip.file}`, skip.reason]);
|
|
318
|
+
}
|
|
319
|
+
return rows;
|
|
320
|
+
}
|
|
321
|
+
|
|
253
322
|
function doctor() {
|
|
254
323
|
const checks = [];
|
|
255
324
|
const pkg = readJSON(join(ROOT, "package.json"));
|
|
@@ -581,6 +650,9 @@ function doctor() {
|
|
|
581
650
|
]);
|
|
582
651
|
}
|
|
583
652
|
|
|
653
|
+
// ── Stylesheets ───────────────────────────────────────────────────────────
|
|
654
|
+
checks.push(...cssChecks());
|
|
655
|
+
|
|
584
656
|
// ── Tooling ────────────────────────────────────────────────────────────────
|
|
585
657
|
checks.push(["section", "Tooling"]);
|
|
586
658
|
checks.push(
|
|
@@ -742,7 +814,7 @@ function lint(args) {
|
|
|
742
814
|
}
|
|
743
815
|
|
|
744
816
|
/** Flags `fix` owns itself; anything else is rejected rather than forwarded. */
|
|
745
|
-
const FIX_FLAGS = new Set(["--no-alias", "--dry-run"]);
|
|
817
|
+
const FIX_FLAGS = new Set(["--no-alias", "--no-css", "--dry-run"]);
|
|
746
818
|
|
|
747
819
|
/**
|
|
748
820
|
* Print the alias pass result.
|
|
@@ -785,6 +857,91 @@ function reportAlias(result, dryRun) {
|
|
|
785
857
|
);
|
|
786
858
|
}
|
|
787
859
|
|
|
860
|
+
/** Prefix for a finding line: red for a browser-visible defect, yellow otherwise. */
|
|
861
|
+
function severityMark(severity) {
|
|
862
|
+
if (severity === "error") return `${c.red}✗${c.reset}`;
|
|
863
|
+
return severity === "warn" ? `${c.yellow}!${c.reset}` : `${c.cyan}i${c.reset}`;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/**
|
|
867
|
+
* The CSS pass of `fix`: report what the analysis found, then remove the subset
|
|
868
|
+
* that is provably dead.
|
|
869
|
+
*
|
|
870
|
+
* Findings that need a human are printed in full here rather than capped, because
|
|
871
|
+
* `--dry-run` is the review surface — `doctor` is the summary, this is the list
|
|
872
|
+
* you read before letting the tool write. Only the advisory (`info`) tail is
|
|
873
|
+
* capped, since "this could be a token" scales with the size of the project.
|
|
874
|
+
*
|
|
875
|
+
* @param {object} params
|
|
876
|
+
* @param {string[]} params.targets - Positional paths from the command line.
|
|
877
|
+
* @param {boolean} params.dryRun
|
|
878
|
+
* @returns {number} Exit status contribution.
|
|
879
|
+
*/
|
|
880
|
+
function cssPass({ targets, dryRun }) {
|
|
881
|
+
console.log(
|
|
882
|
+
`${c.dim}→ css (dedupe declarations · drop dead rules)${dryRun ? " [dry-run]" : ""}${c.reset}`,
|
|
883
|
+
);
|
|
884
|
+
let analysis;
|
|
885
|
+
try {
|
|
886
|
+
analysis = analyzeCss({ root: ROOT, targets, selfDir: SELF_DIR });
|
|
887
|
+
} catch (err) {
|
|
888
|
+
console.log(
|
|
889
|
+
` ${c.red}✗ analysis failed${c.reset} ${c.dim}${err?.message ?? err}${c.reset}`,
|
|
890
|
+
);
|
|
891
|
+
return 1;
|
|
892
|
+
}
|
|
893
|
+
if (analysis.stats.files === 0) {
|
|
894
|
+
console.log(` ${c.dim}no stylesheets found${c.reset}`);
|
|
895
|
+
return 0;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
const manual = analysis.findings.filter((f) => !f.fixable);
|
|
899
|
+
const infoLimit = 10;
|
|
900
|
+
let shownInfo = 0;
|
|
901
|
+
let hiddenInfo = 0;
|
|
902
|
+
for (const f of manual) {
|
|
903
|
+
if (f.severity === "info") {
|
|
904
|
+
if (shownInfo >= infoLimit) {
|
|
905
|
+
hiddenInfo += 1;
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
shownInfo += 1;
|
|
909
|
+
}
|
|
910
|
+
console.log(
|
|
911
|
+
` [${severityMark(f.severity)}] ${f.file}:${f.line} ${c.dim}${f.message}${c.reset}`,
|
|
912
|
+
);
|
|
913
|
+
}
|
|
914
|
+
if (hiddenInfo > 0) {
|
|
915
|
+
console.log(` ${c.dim}…+${hiddenInfo} more suggestion(s)${c.reset}`);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
const result = applyCssFixes({ analysis, dryRun });
|
|
919
|
+
for (const file of result.files) {
|
|
920
|
+
console.log(` ${file.file} ${c.dim}${file.changes.length}${c.reset}`);
|
|
921
|
+
for (const change of file.changes) {
|
|
922
|
+
console.log(` ${c.dim}${change.line}:${c.reset} ${change.message}`);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
for (const err of result.errors) {
|
|
926
|
+
console.log(` ${c.red}✗ ${err.file}${c.reset} ${c.dim}${err.message}${c.reset}`);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
if (result.total === 0) {
|
|
930
|
+
console.log(` ${c.dim}nothing to remove${c.reset}`);
|
|
931
|
+
} else {
|
|
932
|
+
const verb = dryRun ? "would remove" : "removed";
|
|
933
|
+
console.log(
|
|
934
|
+
` ${c.green}✓${c.reset} ${verb} ${result.total} dead declaration(s)/rule(s) in ${result.files.length} file(s)`,
|
|
935
|
+
);
|
|
936
|
+
}
|
|
937
|
+
if (analysis.counts.error > 0) {
|
|
938
|
+
console.log(
|
|
939
|
+
` ${c.red}✗ ${analysis.counts.error} CSS syntax error(s)${c.reset} ${c.dim}— those files were not touched; fix them and run again${c.reset}`,
|
|
940
|
+
);
|
|
941
|
+
}
|
|
942
|
+
return result.errors.length || analysis.counts.error ? 1 : 0;
|
|
943
|
+
}
|
|
944
|
+
|
|
788
945
|
function fix(args) {
|
|
789
946
|
const { flags, paths } = splitArgs(args);
|
|
790
947
|
const unknown = flags.filter((f) => !FIX_FLAGS.has(f));
|
|
@@ -804,7 +961,10 @@ function fix(args) {
|
|
|
804
961
|
reportAlias(result, dryRun);
|
|
805
962
|
aliasStatus = result.status === "error" ? 1 : 0;
|
|
806
963
|
}
|
|
807
|
-
|
|
964
|
+
|
|
965
|
+
const cssStatus = flags.includes("--no-css") ? 0 : cssPass({ targets, dryRun });
|
|
966
|
+
|
|
967
|
+
if (dryRun) return aliasStatus || cssStatus;
|
|
808
968
|
|
|
809
969
|
console.log(`${c.dim}→ eslint --fix (sort imports · drop unused · tidy whitespace)${c.reset}`);
|
|
810
970
|
const eslintStatus = run(requireBin("eslint"), [...targets, "--fix"]);
|
|
@@ -816,7 +976,7 @@ function fix(args) {
|
|
|
816
976
|
} else {
|
|
817
977
|
console.log(`${c.yellow}! prettier not installed — skipping format pass${c.reset}`);
|
|
818
978
|
}
|
|
819
|
-
return aliasStatus || eslintStatus || prettierStatus;
|
|
979
|
+
return aliasStatus || cssStatus || eslintStatus || prettierStatus;
|
|
820
980
|
}
|
|
821
981
|
|
|
822
982
|
function format(args) {
|
|
@@ -952,8 +1112,8 @@ ${c.bold}Usage${c.reset}
|
|
|
952
1112
|
${c.bold}Commands${c.reset}
|
|
953
1113
|
${c.bold}doctor${c.reset} Health-check the current project
|
|
954
1114
|
${c.bold}lint${c.reset} [paths] Run ESLint (report only)
|
|
955
|
-
${c.bold}fix${c.reset} [paths] Alias imports (../ → @/) + ESLint --fix
|
|
956
|
-
unused, tidy whitespace) + Prettier
|
|
1115
|
+
${c.bold}fix${c.reset} [paths] Alias imports (../ → @/) + CSS dead-code removal + ESLint --fix
|
|
1116
|
+
(sort imports, remove unused, tidy whitespace) + Prettier
|
|
957
1117
|
${c.bold}format${c.reset} [paths] Prettier --write
|
|
958
1118
|
${c.bold}gen api${c.reset} <src> Generate Zod schemas + types + service classes from an OpenAPI spec
|
|
959
1119
|
(e.g. tempest gen api http://127.0.0.1:8000/openapi.json --out src/api)
|
|
@@ -961,8 +1121,10 @@ ${c.bold}Commands${c.reset}
|
|
|
961
1121
|
(e.g. tempest gen icons --out src/icons.generated.ts --dir src)
|
|
962
1122
|
|
|
963
1123
|
${c.bold}fix options${c.reset}
|
|
964
|
-
--dry-run List the imports that would be rewritten;
|
|
965
|
-
|
|
1124
|
+
--dry-run List every CSS finding and the imports that would be rewritten;
|
|
1125
|
+
write nothing
|
|
1126
|
+
--no-alias Skip the alias pass
|
|
1127
|
+
--no-css Skip the CSS pass (analysis and dead-code removal)
|
|
966
1128
|
|
|
967
1129
|
${c.bold}Options${c.reset}
|
|
968
1130
|
-h, --help Show this help
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=7,t=9,n=3;function r(e){return`var(--tempest-chart-${e})`}function i(e,t,n){if(!Number.isFinite(e))return 0;let r=Math.min(t,n),i=Math.max(t,n);return i===r?.5:Math.min(1,Math.max(0,(e-r)/(i-r)))}function a(e,t){return Math.min(t,Math.max(1,Math.round(e*(t-1))+1))}function o(e){let{min:t,max:n,ordinal:o=!1}=e,s=o?3:1,c=7-s+1;return e=>r(`sequential-${s+a(i(e,t,n),c)-1}`)}function s(e){let{min:t,max:n,center:i=0}=e,o=Math.abs(i-Math.min(t,n)),s=Math.abs(Math.max(t,n)-i);return e=>r(!Number.isFinite(e)||e===i?`diverging-5`:e<i?o===0?`diverging-5`:`diverging-${5-a(Math.min(1,(i-e)/o),4)}`:s===0?`diverging-5`:`diverging-${5+a(Math.min(1,(e-i)/s),4)}`)}function c(e){let t=e===`sequential`?7:9;return Array.from({length:t},(t,n)=>r(`${e}-${n+1}`))}exports.DIVERGING_STEP_COUNT=t,exports.ORDINAL_START_STEP=n,exports.SEQUENTIAL_STEP_COUNT=e,exports.divergingScale=s,exports.scaleSteps=c,exports.sequentialScale=o;
|
|
2
|
+
//# sourceMappingURL=scales.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scales.cjs","names":[],"sources":["../../src/charts/scales.ts"],"sourcesContent":["/** How many steps the sequential token scale has. */\nexport const SEQUENTIAL_STEP_COUNT = 7;\n\n/** How many steps the diverging token scale has, midpoint included. */\nexport const DIVERGING_STEP_COUNT = 9;\n\n/**\n * First sequential step that clears 2:1 against the chart surface.\n *\n * A sequential scale may let its near-zero end recede into the surface — on a\n * heatmap that is exactly what \"almost nothing\" should look like. An **ordinal**\n * scale may not: every step is a discrete mark someone has to see. Starting an\n * ordinal ramp here is the difference.\n */\nexport const ORDINAL_START_STEP = 3;\n\n/** A `var(--tempest-chart-…)` reference, so the value follows the active theme. */\nexport type ChartColorToken = string;\n\n/** Reference a token by name rather than interpolating the string at each call site. */\nfunction token(name: string): ChartColorToken {\n return `var(--tempest-chart-${name})`;\n}\n\n/**\n * Clamp `value` into `0…1` against a domain, tolerating a reversed or empty one.\n *\n * A zero-width domain (every datum equal) would otherwise divide by zero and paint\n * the whole chart `NaN`; it resolves to the middle of the scale instead, which is\n * the honest reading of \"no variation\".\n */\nfunction normalize(value: number, min: number, max: number): number {\n if (!Number.isFinite(value)) return 0;\n const lo = Math.min(min, max);\n const hi = Math.max(min, max);\n if (hi === lo) return 0.5;\n return Math.min(1, Math.max(0, (value - lo) / (hi - lo)));\n}\n\n/** Map a `0…1` position onto `1…steps`, inclusive. */\nfunction stepOf(t: number, steps: number): number {\n return Math.min(steps, Math.max(1, Math.round(t * (steps - 1)) + 1));\n}\n\nexport interface SequentialScaleOptions {\n /** Lowest value in the data. */\n min: number;\n /** Highest value in the data. */\n max: number;\n /**\n * Keep every step visible against the surface, for discrete ordered marks.\n *\n * Off by default: a heatmap *wants* its near-zero cells to recede. Turn it on\n * for tiers, funnel stages or anything where each step is its own mark.\n */\n ordinal?: boolean;\n}\n\n/**\n * Build a magnitude scale over the sequential tokens.\n *\n * Returns `var(--tempest-chart-sequential-N)` rather than a hex string, so a\n * heatmap painted once follows the theme — including dark mode, whose steps are\n * chosen for the dark surface rather than flipped.\n *\n * @example\n * const color = sequentialScale({ min: 0, max: 250 });\n * <rect fill={color(value)} />\n *\n * @param options - The data domain, and whether every step must stay visible.\n * @returns A function from value to a CSS colour reference.\n */\nexport function sequentialScale(\n options: SequentialScaleOptions,\n): (value: number) => ChartColorToken {\n const { min, max, ordinal = false } = options;\n const first = ordinal ? ORDINAL_START_STEP : 1;\n const span = SEQUENTIAL_STEP_COUNT - first + 1;\n return (value) => token(`sequential-${first + stepOf(normalize(value, min, max), span) - 1}`);\n}\n\nexport interface DivergingScaleOptions {\n /** Lowest value in the data. */\n min: number;\n /** Highest value in the data. */\n max: number;\n /**\n * The value that means \"no deviation\". Default `0`.\n *\n * It is a parameter because the interesting midpoint is often not zero — a\n * budget variance diverges around the target, not around nothing.\n */\n center?: number;\n}\n\n/**\n * Build a polarity scale over the diverging tokens.\n *\n * Each arm is scaled against its **own** distance from the centre, so an asymmetric\n * domain (say −5…+80) still uses the full cool arm for its small negatives. Scaling\n * both arms by the wider one — the easy mistake — would collapse every negative\n * into the step next to the midpoint and hide the sign entirely.\n *\n * @example\n * const color = divergingScale({ min: -12, max: 40 }); // centre 0\n * const budget = divergingScale({ min: 80, max: 130, center: 100 });\n *\n * @param options - The data domain and the neutral centre.\n * @returns A function from value to a CSS colour reference.\n */\nexport function divergingScale(options: DivergingScaleOptions): (value: number) => ChartColorToken {\n const { min, max, center = 0 } = options;\n const mid = Math.ceil(DIVERGING_STEP_COUNT / 2);\n const armSteps = mid - 1;\n const coolSpan = Math.abs(center - Math.min(min, max));\n const warmSpan = Math.abs(Math.max(min, max) - center);\n\n return (value) => {\n if (!Number.isFinite(value) || value === center) return token(`diverging-${mid}`);\n if (value < center) {\n if (coolSpan === 0) return token(`diverging-${mid}`);\n const t = Math.min(1, (center - value) / coolSpan);\n // Step 1 is the cool extreme, so a bigger deviation walks toward it.\n return token(`diverging-${mid - stepOf(t, armSteps)}`);\n }\n if (warmSpan === 0) return token(`diverging-${mid}`);\n const t = Math.min(1, (value - center) / warmSpan);\n return token(`diverging-${mid + stepOf(t, armSteps)}`);\n };\n}\n\n/**\n * Every step of a token scale, in order — for rendering a legend.\n *\n * A continuous scale needs a legend showing the ramp with its end labels; without\n * one the reader has no way to turn a colour back into a number.\n *\n * @param kind - Which scale.\n * @returns The token references, lightest/coolest first.\n */\nexport function scaleSteps(kind: \"sequential\" | \"diverging\"): ChartColorToken[] {\n const count = kind === \"sequential\" ? SEQUENTIAL_STEP_COUNT : DIVERGING_STEP_COUNT;\n return Array.from({ length: count }, (_, i) => token(`${kind}-${i + 1}`));\n}\n"],"mappings":"AACA,IAAa,EAAwB,EAGxB,EAAuB,EAUvB,EAAqB,EAMlC,SAAS,EAAM,EAA+B,CAC1C,MAAO,uBAAuB,EAAK,EACvC,CASA,SAAS,EAAU,EAAe,EAAa,EAAqB,CAChE,GAAI,CAAC,OAAO,SAAS,CAAK,EAAG,MAAO,GACpC,IAAM,EAAK,KAAK,IAAI,EAAK,CAAG,EACtB,EAAK,KAAK,IAAI,EAAK,CAAG,EAE5B,OADI,IAAO,EAAW,GACf,KAAK,IAAI,EAAG,KAAK,IAAI,GAAI,EAAQ,IAAO,EAAK,EAAG,CAAC,CAC5D,CAGA,SAAS,EAAO,EAAW,EAAuB,CAC9C,OAAO,KAAK,IAAI,EAAO,KAAK,IAAI,EAAG,KAAK,MAAM,GAAK,EAAQ,EAAE,EAAI,CAAC,CAAC,CACvE,CA8BA,SAAgB,EACZ,EACkC,CAClC,GAAM,CAAE,MAAK,MAAK,UAAU,IAAU,EAChC,EAAQ,EAAA,EAA+B,EACvC,EAAA,EAA+B,EAAQ,EAC7C,MAAQ,IAAU,EAAM,cAAc,EAAQ,EAAO,EAAU,EAAO,EAAK,CAAG,EAAG,CAAI,EAAI,GAAG,CAChG,CA+BA,SAAgB,EAAe,EAAoE,CAC/F,GAAM,CAAE,MAAK,MAAK,SAAS,GAAM,EAG3B,EAAW,KAAK,IAAI,EAAS,KAAK,IAAI,EAAK,CAAG,CAAC,EAC/C,EAAW,KAAK,IAAI,KAAK,IAAI,EAAK,CAAG,EAAI,CAAM,EAErD,MAAQ,IACoD,EAApD,CAAC,OAAO,SAAS,CAAK,GAAK,IAAU,EAAqB,cAC1D,EAAQ,EACJ,IAAa,EAAgB,cAGpB,aAAa,EAAM,EAFtB,KAAK,IAAI,GAAI,EAAS,GAAS,CAEF,EAAG,CAAQ,IAElD,IAAa,EAAgB,cAEpB,aAAa,EAAM,EADtB,KAAK,IAAI,GAAI,EAAQ,GAAU,CACF,EAAG,CAAQ,GAT8B,CAWxF,CAWA,SAAgB,EAAW,EAAqD,CAC5E,IAAM,EAAQ,IAAS,aAAA,EAAA,EACvB,OAAO,MAAM,KAAK,CAAE,OAAQ,CAAM,GAAI,EAAG,IAAM,EAAM,GAAG,EAAK,GAAG,EAAI,GAAG,CAAC,CAC5E"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/charts/scales.ts
|
|
2
|
+
var e = 7, t = 9, n = 3;
|
|
3
|
+
function r(e) {
|
|
4
|
+
return `var(--tempest-chart-${e})`;
|
|
5
|
+
}
|
|
6
|
+
function i(e, t, n) {
|
|
7
|
+
if (!Number.isFinite(e)) return 0;
|
|
8
|
+
let r = Math.min(t, n), i = Math.max(t, n);
|
|
9
|
+
return i === r ? .5 : Math.min(1, Math.max(0, (e - r) / (i - r)));
|
|
10
|
+
}
|
|
11
|
+
function a(e, t) {
|
|
12
|
+
return Math.min(t, Math.max(1, Math.round(e * (t - 1)) + 1));
|
|
13
|
+
}
|
|
14
|
+
function o(e) {
|
|
15
|
+
let { min: t, max: n, ordinal: o = !1 } = e, s = o ? 3 : 1, c = 7 - s + 1;
|
|
16
|
+
return (e) => r(`sequential-${s + a(i(e, t, n), c) - 1}`);
|
|
17
|
+
}
|
|
18
|
+
function s(e) {
|
|
19
|
+
let { min: t, max: n, center: i = 0 } = e, o = Math.abs(i - Math.min(t, n)), s = Math.abs(Math.max(t, n) - i);
|
|
20
|
+
return (e) => r(!Number.isFinite(e) || e === i ? "diverging-5" : e < i ? o === 0 ? "diverging-5" : `diverging-${5 - a(Math.min(1, (i - e) / o), 4)}` : s === 0 ? "diverging-5" : `diverging-${5 + a(Math.min(1, (e - i) / s), 4)}`);
|
|
21
|
+
}
|
|
22
|
+
function c(e) {
|
|
23
|
+
let t = e === "sequential" ? 7 : 9;
|
|
24
|
+
return Array.from({ length: t }, (t, n) => r(`${e}-${n + 1}`));
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { t as DIVERGING_STEP_COUNT, n as ORDINAL_START_STEP, e as SEQUENTIAL_STEP_COUNT, s as divergingScale, c as scaleSteps, o as sequentialScale };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=scales.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scales.js","names":[],"sources":["../../src/charts/scales.ts"],"sourcesContent":["/** How many steps the sequential token scale has. */\nexport const SEQUENTIAL_STEP_COUNT = 7;\n\n/** How many steps the diverging token scale has, midpoint included. */\nexport const DIVERGING_STEP_COUNT = 9;\n\n/**\n * First sequential step that clears 2:1 against the chart surface.\n *\n * A sequential scale may let its near-zero end recede into the surface — on a\n * heatmap that is exactly what \"almost nothing\" should look like. An **ordinal**\n * scale may not: every step is a discrete mark someone has to see. Starting an\n * ordinal ramp here is the difference.\n */\nexport const ORDINAL_START_STEP = 3;\n\n/** A `var(--tempest-chart-…)` reference, so the value follows the active theme. */\nexport type ChartColorToken = string;\n\n/** Reference a token by name rather than interpolating the string at each call site. */\nfunction token(name: string): ChartColorToken {\n return `var(--tempest-chart-${name})`;\n}\n\n/**\n * Clamp `value` into `0…1` against a domain, tolerating a reversed or empty one.\n *\n * A zero-width domain (every datum equal) would otherwise divide by zero and paint\n * the whole chart `NaN`; it resolves to the middle of the scale instead, which is\n * the honest reading of \"no variation\".\n */\nfunction normalize(value: number, min: number, max: number): number {\n if (!Number.isFinite(value)) return 0;\n const lo = Math.min(min, max);\n const hi = Math.max(min, max);\n if (hi === lo) return 0.5;\n return Math.min(1, Math.max(0, (value - lo) / (hi - lo)));\n}\n\n/** Map a `0…1` position onto `1…steps`, inclusive. */\nfunction stepOf(t: number, steps: number): number {\n return Math.min(steps, Math.max(1, Math.round(t * (steps - 1)) + 1));\n}\n\nexport interface SequentialScaleOptions {\n /** Lowest value in the data. */\n min: number;\n /** Highest value in the data. */\n max: number;\n /**\n * Keep every step visible against the surface, for discrete ordered marks.\n *\n * Off by default: a heatmap *wants* its near-zero cells to recede. Turn it on\n * for tiers, funnel stages or anything where each step is its own mark.\n */\n ordinal?: boolean;\n}\n\n/**\n * Build a magnitude scale over the sequential tokens.\n *\n * Returns `var(--tempest-chart-sequential-N)` rather than a hex string, so a\n * heatmap painted once follows the theme — including dark mode, whose steps are\n * chosen for the dark surface rather than flipped.\n *\n * @example\n * const color = sequentialScale({ min: 0, max: 250 });\n * <rect fill={color(value)} />\n *\n * @param options - The data domain, and whether every step must stay visible.\n * @returns A function from value to a CSS colour reference.\n */\nexport function sequentialScale(\n options: SequentialScaleOptions,\n): (value: number) => ChartColorToken {\n const { min, max, ordinal = false } = options;\n const first = ordinal ? ORDINAL_START_STEP : 1;\n const span = SEQUENTIAL_STEP_COUNT - first + 1;\n return (value) => token(`sequential-${first + stepOf(normalize(value, min, max), span) - 1}`);\n}\n\nexport interface DivergingScaleOptions {\n /** Lowest value in the data. */\n min: number;\n /** Highest value in the data. */\n max: number;\n /**\n * The value that means \"no deviation\". Default `0`.\n *\n * It is a parameter because the interesting midpoint is often not zero — a\n * budget variance diverges around the target, not around nothing.\n */\n center?: number;\n}\n\n/**\n * Build a polarity scale over the diverging tokens.\n *\n * Each arm is scaled against its **own** distance from the centre, so an asymmetric\n * domain (say −5…+80) still uses the full cool arm for its small negatives. Scaling\n * both arms by the wider one — the easy mistake — would collapse every negative\n * into the step next to the midpoint and hide the sign entirely.\n *\n * @example\n * const color = divergingScale({ min: -12, max: 40 }); // centre 0\n * const budget = divergingScale({ min: 80, max: 130, center: 100 });\n *\n * @param options - The data domain and the neutral centre.\n * @returns A function from value to a CSS colour reference.\n */\nexport function divergingScale(options: DivergingScaleOptions): (value: number) => ChartColorToken {\n const { min, max, center = 0 } = options;\n const mid = Math.ceil(DIVERGING_STEP_COUNT / 2);\n const armSteps = mid - 1;\n const coolSpan = Math.abs(center - Math.min(min, max));\n const warmSpan = Math.abs(Math.max(min, max) - center);\n\n return (value) => {\n if (!Number.isFinite(value) || value === center) return token(`diverging-${mid}`);\n if (value < center) {\n if (coolSpan === 0) return token(`diverging-${mid}`);\n const t = Math.min(1, (center - value) / coolSpan);\n // Step 1 is the cool extreme, so a bigger deviation walks toward it.\n return token(`diverging-${mid - stepOf(t, armSteps)}`);\n }\n if (warmSpan === 0) return token(`diverging-${mid}`);\n const t = Math.min(1, (value - center) / warmSpan);\n return token(`diverging-${mid + stepOf(t, armSteps)}`);\n };\n}\n\n/**\n * Every step of a token scale, in order — for rendering a legend.\n *\n * A continuous scale needs a legend showing the ramp with its end labels; without\n * one the reader has no way to turn a colour back into a number.\n *\n * @param kind - Which scale.\n * @returns The token references, lightest/coolest first.\n */\nexport function scaleSteps(kind: \"sequential\" | \"diverging\"): ChartColorToken[] {\n const count = kind === \"sequential\" ? SEQUENTIAL_STEP_COUNT : DIVERGING_STEP_COUNT;\n return Array.from({ length: count }, (_, i) => token(`${kind}-${i + 1}`));\n}\n"],"mappings":";AACA,IAAa,IAAwB,GAGxB,IAAuB,GAUvB,IAAqB;AAMlC,SAAS,EAAM,GAA+B;CAC1C,OAAO,uBAAuB,EAAK;AACvC;AASA,SAAS,EAAU,GAAe,GAAa,GAAqB;CAChE,IAAI,CAAC,OAAO,SAAS,CAAK,GAAG,OAAO;CACpC,IAAM,IAAK,KAAK,IAAI,GAAK,CAAG,GACtB,IAAK,KAAK,IAAI,GAAK,CAAG;CAE5B,OADI,MAAO,IAAW,KACf,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,IAAQ,MAAO,IAAK,EAAG,CAAC;AAC5D;AAGA,SAAS,EAAO,GAAW,GAAuB;CAC9C,OAAO,KAAK,IAAI,GAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,IAAQ,EAAE,IAAI,CAAC,CAAC;AACvE;AA8BA,SAAgB,EACZ,GACkC;CAClC,IAAM,EAAE,QAAK,QAAK,aAAU,OAAU,GAChC,IAAQ,IAAA,IAA+B,GACvC,IAAA,IAA+B,IAAQ;CAC7C,QAAQ,MAAU,EAAM,cAAc,IAAQ,EAAO,EAAU,GAAO,GAAK,CAAG,GAAG,CAAI,IAAI,GAAG;AAChG;AA+BA,SAAgB,EAAe,GAAoE;CAC/F,IAAM,EAAE,QAAK,QAAK,YAAS,MAAM,GAG3B,IAAW,KAAK,IAAI,IAAS,KAAK,IAAI,GAAK,CAAG,CAAC,GAC/C,IAAW,KAAK,IAAI,KAAK,IAAI,GAAK,CAAG,IAAI,CAAM;CAErD,QAAQ,MACoD,EAApD,CAAC,OAAO,SAAS,CAAK,KAAK,MAAU,IAAqB,gBAC1D,IAAQ,IACJ,MAAa,IAAgB,gBAGpB,aAAa,IAAM,EAFtB,KAAK,IAAI,IAAI,IAAS,KAAS,CAEF,GAAG,CAAQ,MAElD,MAAa,IAAgB,gBAEpB,aAAa,IAAM,EADtB,KAAK,IAAI,IAAI,IAAQ,KAAU,CACF,GAAG,CAAQ,GAT8B;AAWxF;AAWA,SAAgB,EAAW,GAAqD;CAC5E,IAAM,IAAQ,MAAS,eAAA,IAAA;CACvB,OAAO,MAAM,KAAK,EAAE,QAAQ,EAAM,IAAI,GAAG,MAAM,EAAM,GAAG,EAAK,GAAG,IAAI,GAAG,CAAC;AAC5E"}
|
package/dist/charts.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./charts/
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./charts/scales.cjs"),t=require("./charts/palette.cjs"),n=require("./charts/use-chart-colors.cjs"),r=require("./charts/AreaChart.cjs"),i=require("./charts/BarChart.cjs"),a=require("./charts/LineChart.cjs"),o=require("./charts/PieChart.cjs"),s=require("./charts/RadarChart.cjs");exports.AreaChart=r.AreaChart,exports.BarChart=i.BarChart,exports.CHART_COLOR_TOKEN_COUNT=t.CHART_COLOR_TOKEN_COUNT,exports.DEFAULT_CHART_COLORS=t.DEFAULT_CHART_COLORS,exports.DIVERGING_STEP_COUNT=e.DIVERGING_STEP_COUNT,exports.LineChart=a.LineChart,exports.ORDINAL_START_STEP=e.ORDINAL_START_STEP,exports.PieChart=o.PieChart,exports.RadarChart=s.RadarChart,exports.SEQUENTIAL_STEP_COUNT=e.SEQUENTIAL_STEP_COUNT,exports.divergingScale=e.divergingScale,exports.resolveChartChrome=t.resolveChartChrome,exports.resolveChartColors=t.resolveChartColors,exports.scaleSteps=e.scaleSteps,exports.sequentialScale=e.sequentialScale,exports.useChartColors=n.useChartColors;
|
package/dist/charts.d.ts
CHANGED
|
@@ -60,6 +60,9 @@ export declare interface CartesianChartProps {
|
|
|
60
60
|
/** How many `--tempest-chart-N` tokens the SDK ships. */
|
|
61
61
|
export declare const CHART_COLOR_TOKEN_COUNT = 8;
|
|
62
62
|
|
|
63
|
+
/** A `var(--tempest-chart-…)` reference, so the value follows the active theme. */
|
|
64
|
+
export declare type ChartColorToken = string;
|
|
65
|
+
|
|
63
66
|
/**
|
|
64
67
|
* Tabular data consumed by every chart: an array of rows, where each row maps a
|
|
65
68
|
* column key to a string (label) or number (value).
|
|
@@ -77,6 +80,40 @@ export declare type ChartData = Array<Record<string, string | number>>;
|
|
|
77
80
|
*/
|
|
78
81
|
export declare const DEFAULT_CHART_COLORS: string[];
|
|
79
82
|
|
|
83
|
+
/** How many steps the diverging token scale has, midpoint included. */
|
|
84
|
+
export declare const DIVERGING_STEP_COUNT = 9;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Build a polarity scale over the diverging tokens.
|
|
88
|
+
*
|
|
89
|
+
* Each arm is scaled against its **own** distance from the centre, so an asymmetric
|
|
90
|
+
* domain (say −5…+80) still uses the full cool arm for its small negatives. Scaling
|
|
91
|
+
* both arms by the wider one — the easy mistake — would collapse every negative
|
|
92
|
+
* into the step next to the midpoint and hide the sign entirely.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* const color = divergingScale({ min: -12, max: 40 }); // centre 0
|
|
96
|
+
* const budget = divergingScale({ min: 80, max: 130, center: 100 });
|
|
97
|
+
*
|
|
98
|
+
* @param options - The data domain and the neutral centre.
|
|
99
|
+
* @returns A function from value to a CSS colour reference.
|
|
100
|
+
*/
|
|
101
|
+
export declare function divergingScale(options: DivergingScaleOptions): (value: number) => ChartColorToken;
|
|
102
|
+
|
|
103
|
+
export declare interface DivergingScaleOptions {
|
|
104
|
+
/** Lowest value in the data. */
|
|
105
|
+
min: number;
|
|
106
|
+
/** Highest value in the data. */
|
|
107
|
+
max: number;
|
|
108
|
+
/**
|
|
109
|
+
* The value that means "no deviation". Default `0`.
|
|
110
|
+
*
|
|
111
|
+
* It is a parameter because the interesting midpoint is often not zero — a
|
|
112
|
+
* budget variance diverges around the target, not around nothing.
|
|
113
|
+
*/
|
|
114
|
+
center?: number;
|
|
115
|
+
}
|
|
116
|
+
|
|
80
117
|
/**
|
|
81
118
|
* LineChart — themed wrapper over recharts `LineChart`.
|
|
82
119
|
*
|
|
@@ -88,6 +125,16 @@ export declare const DEFAULT_CHART_COLORS: string[];
|
|
|
88
125
|
*/
|
|
89
126
|
export declare function LineChart({ data, index, categories, colors, height, width, showLegend, showGrid, showTooltip, valueFormatter, className, }: CartesianChartProps): JSX.Element;
|
|
90
127
|
|
|
128
|
+
/**
|
|
129
|
+
* First sequential step that clears 2:1 against the chart surface.
|
|
130
|
+
*
|
|
131
|
+
* A sequential scale may let its near-zero end recede into the surface — on a
|
|
132
|
+
* heatmap that is exactly what "almost nothing" should look like. An **ordinal**
|
|
133
|
+
* scale may not: every step is a discrete mark someone has to see. Starting an
|
|
134
|
+
* ordinal ramp here is the difference.
|
|
135
|
+
*/
|
|
136
|
+
export declare const ORDINAL_START_STEP = 3;
|
|
137
|
+
|
|
91
138
|
/**
|
|
92
139
|
* PieChart — themed wrapper over recharts `PieChart`.
|
|
93
140
|
*
|
|
@@ -165,6 +212,50 @@ export declare function resolveChartChrome(part: "grid" | "axis", element?: Elem
|
|
|
165
212
|
*/
|
|
166
213
|
export declare function resolveChartColors(element?: Element | null): string[];
|
|
167
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Every step of a token scale, in order — for rendering a legend.
|
|
217
|
+
*
|
|
218
|
+
* A continuous scale needs a legend showing the ramp with its end labels; without
|
|
219
|
+
* one the reader has no way to turn a colour back into a number.
|
|
220
|
+
*
|
|
221
|
+
* @param kind - Which scale.
|
|
222
|
+
* @returns The token references, lightest/coolest first.
|
|
223
|
+
*/
|
|
224
|
+
export declare function scaleSteps(kind: "sequential" | "diverging"): ChartColorToken[];
|
|
225
|
+
|
|
226
|
+
/** How many steps the sequential token scale has. */
|
|
227
|
+
export declare const SEQUENTIAL_STEP_COUNT = 7;
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Build a magnitude scale over the sequential tokens.
|
|
231
|
+
*
|
|
232
|
+
* Returns `var(--tempest-chart-sequential-N)` rather than a hex string, so a
|
|
233
|
+
* heatmap painted once follows the theme — including dark mode, whose steps are
|
|
234
|
+
* chosen for the dark surface rather than flipped.
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* const color = sequentialScale({ min: 0, max: 250 });
|
|
238
|
+
* <rect fill={color(value)} />
|
|
239
|
+
*
|
|
240
|
+
* @param options - The data domain, and whether every step must stay visible.
|
|
241
|
+
* @returns A function from value to a CSS colour reference.
|
|
242
|
+
*/
|
|
243
|
+
export declare function sequentialScale(options: SequentialScaleOptions): (value: number) => ChartColorToken;
|
|
244
|
+
|
|
245
|
+
export declare interface SequentialScaleOptions {
|
|
246
|
+
/** Lowest value in the data. */
|
|
247
|
+
min: number;
|
|
248
|
+
/** Highest value in the data. */
|
|
249
|
+
max: number;
|
|
250
|
+
/**
|
|
251
|
+
* Keep every step visible against the surface, for discrete ordered marks.
|
|
252
|
+
*
|
|
253
|
+
* Off by default: a heatmap *wants* its near-zero cells to recede. Turn it on
|
|
254
|
+
* for tiers, funnel stages or anything where each step is its own mark.
|
|
255
|
+
*/
|
|
256
|
+
ordinal?: boolean;
|
|
257
|
+
}
|
|
258
|
+
|
|
168
259
|
/**
|
|
169
260
|
* Theme-aware series colors for a chart.
|
|
170
261
|
*
|
package/dist/charts.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
1
|
+
import { DIVERGING_STEP_COUNT as e, ORDINAL_START_STEP as t, SEQUENTIAL_STEP_COUNT as n, divergingScale as r, scaleSteps as i, sequentialScale as a } from "./charts/scales.js";
|
|
2
|
+
import { CHART_COLOR_TOKEN_COUNT as o, DEFAULT_CHART_COLORS as s, resolveChartChrome as c, resolveChartColors as l } from "./charts/palette.js";
|
|
3
|
+
import { useChartColors as u } from "./charts/use-chart-colors.js";
|
|
4
|
+
import { AreaChart as d } from "./charts/AreaChart.js";
|
|
5
|
+
import { BarChart as f } from "./charts/BarChart.js";
|
|
6
|
+
import { LineChart as p } from "./charts/LineChart.js";
|
|
7
|
+
import { PieChart as m } from "./charts/PieChart.js";
|
|
8
|
+
import { RadarChart as h } from "./charts/RadarChart.js";
|
|
9
|
+
export { d as AreaChart, f as BarChart, o as CHART_COLOR_TOKEN_COUNT, s as DEFAULT_CHART_COLORS, e as DIVERGING_STEP_COUNT, p as LineChart, t as ORDINAL_START_STEP, m as PieChart, h as RadarChart, n as SEQUENTIAL_STEP_COUNT, r as divergingScale, c as resolveChartChrome, l as resolveChartColors, i as scaleSteps, a as sequentialScale, u as useChartColors };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BottomNavigation.module.cjs","names":[],"sources":["../../../src/components/BottomNavigation/BottomNavigation.module.css"],"sourcesContent":[".bar {\n display: flex;\n width: 100%;\n background: var(--tempest-surface);\n border-top: 1px solid var(--tempest-border);\n padding-bottom: env(safe-area-inset-bottom, 0);\n font-family: var(--tempest-font-sans);\n}\n\n.item {\n flex: 1 1 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 2px;\n padding: 8px 4px;\n background: none;\n border: 0;\n cursor: pointer;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-2xs);\n transition: color var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out);\n min-height: 56px;\n}\n\n.item:hover {\n color: var(--tempest-text);\n}\n\n.item.active {\n color: var(--tempest-primary);\n}\n\n.item:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.iconWrap {\n position: relative;\n display: inline-flex;\n}\n\n.icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n font-size: 20px;\n}\n\n.badge {\n position: absolute;\n top: -4px;\n right: -8px;\n min-width: 14px;\n height: 14px;\n padding: 0 4px;\n border-radius: var(--tempest-radius-full);\n background: var(--tempest-danger-solid);\n color: var(--tempest-danger-on);\n font-size: 10px;\n line-height: 14px;\n text-align: center;\n font-weight: var(--tempest-weight-semibold);\n}\n\n.label {\n line-height: 1;\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"BottomNavigation.module.cjs","names":[],"sources":["../../../src/components/BottomNavigation/BottomNavigation.module.css"],"sourcesContent":[".bar {\n display: flex;\n width: 100%;\n background: var(--tempest-surface);\n border-top: 1px solid var(--tempest-border);\n padding-bottom: env(safe-area-inset-bottom, 0);\n font-family: var(--tempest-font-sans);\n}\n\n.item {\n flex: 1 1 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 2px;\n padding: 8px 4px;\n background: none;\n border: 0;\n cursor: pointer;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-2xs);\n transition: color var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out);\n min-height: 56px;\n}\n\n.item:hover {\n color: var(--tempest-text);\n}\n\n.item.active {\n color: var(--tempest-primary);\n}\n\n.item:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.iconWrap {\n position: relative;\n display: inline-flex;\n}\n\n.icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n font-size: 20px;\n}\n\n.badge {\n position: absolute;\n top: -4px;\n right: -8px;\n min-width: 14px;\n height: 14px;\n padding: 0 4px;\n border-radius: var(--tempest-radius-full);\n background: var(--tempest-danger-solid);\n color: var(--tempest-danger-on, #fff);\n font-size: 10px;\n line-height: 14px;\n text-align: center;\n font-weight: var(--tempest-weight-semibold);\n}\n\n.label {\n line-height: 1;\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BottomNavigation.module.js","names":[],"sources":["../../../src/components/BottomNavigation/BottomNavigation.module.css"],"sourcesContent":[".bar {\n display: flex;\n width: 100%;\n background: var(--tempest-surface);\n border-top: 1px solid var(--tempest-border);\n padding-bottom: env(safe-area-inset-bottom, 0);\n font-family: var(--tempest-font-sans);\n}\n\n.item {\n flex: 1 1 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 2px;\n padding: 8px 4px;\n background: none;\n border: 0;\n cursor: pointer;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-2xs);\n transition: color var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out);\n min-height: 56px;\n}\n\n.item:hover {\n color: var(--tempest-text);\n}\n\n.item.active {\n color: var(--tempest-primary);\n}\n\n.item:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.iconWrap {\n position: relative;\n display: inline-flex;\n}\n\n.icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n font-size: 20px;\n}\n\n.badge {\n position: absolute;\n top: -4px;\n right: -8px;\n min-width: 14px;\n height: 14px;\n padding: 0 4px;\n border-radius: var(--tempest-radius-full);\n background: var(--tempest-danger-solid);\n color: var(--tempest-danger-on);\n font-size: 10px;\n line-height: 14px;\n text-align: center;\n font-weight: var(--tempest-weight-semibold);\n}\n\n.label {\n line-height: 1;\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"BottomNavigation.module.js","names":[],"sources":["../../../src/components/BottomNavigation/BottomNavigation.module.css"],"sourcesContent":[".bar {\n display: flex;\n width: 100%;\n background: var(--tempest-surface);\n border-top: 1px solid var(--tempest-border);\n padding-bottom: env(safe-area-inset-bottom, 0);\n font-family: var(--tempest-font-sans);\n}\n\n.item {\n flex: 1 1 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 2px;\n padding: 8px 4px;\n background: none;\n border: 0;\n cursor: pointer;\n color: var(--tempest-text-muted);\n font-size: var(--tempest-text-2xs);\n transition: color var(--tempest-duration-fast, 120ms) var(--tempest-ease-out, ease-out);\n min-height: 56px;\n}\n\n.item:hover {\n color: var(--tempest-text);\n}\n\n.item.active {\n color: var(--tempest-primary);\n}\n\n.item:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.iconWrap {\n position: relative;\n display: inline-flex;\n}\n\n.icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n line-height: 1;\n font-size: 20px;\n}\n\n.badge {\n position: absolute;\n top: -4px;\n right: -8px;\n min-width: 14px;\n height: 14px;\n padding: 0 4px;\n border-radius: var(--tempest-radius-full);\n background: var(--tempest-danger-solid);\n color: var(--tempest-danger-on, #fff);\n font-size: 10px;\n line-height: 14px;\n text-align: center;\n font-weight: var(--tempest-weight-semibold);\n}\n\n.label {\n line-height: 1;\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Carousel.module.cjs","names":[],"sources":["../../../src/components/Carousel/Carousel.module.css"],"sourcesContent":[".root {\n position: relative;\n width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.root:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.viewport {\n overflow: hidden;\n border-radius: var(--tempest-radius-lg);\n}\n\n.track {\n display: flex;\n transition: transform var(--tempest-duration-
|
|
1
|
+
{"version":3,"file":"Carousel.module.cjs","names":[],"sources":["../../../src/components/Carousel/Carousel.module.css"],"sourcesContent":[".root {\n position: relative;\n width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.root:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.viewport {\n overflow: hidden;\n border-radius: var(--tempest-radius-lg);\n}\n\n.track {\n display: flex;\n transition: transform var(--tempest-duration-base) var(--tempest-ease-out);\n}\n\n.slide {\n flex: 0 0 100%;\n min-width: 0;\n}\n\n.arrow {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n background-color: var(--tempest-bg);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-full);\n box-shadow: var(--tempest-shadow-md);\n color: var(--tempest-text);\n font-size: var(--tempest-text-xl);\n line-height: 1;\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .arrow:hover:not(:disabled) {\n background-color: var(--tempest-surface);\n }\n}\n\n.arrow:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.arrow:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.prev {\n left: var(--tempest-space-2);\n}\n\n.next {\n right: var(--tempest-space-2);\n}\n\n.dots {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-space-2);\n margin-top: var(--tempest-space-3);\n}\n\n.dot {\n width: 0.5rem;\n height: 0.5rem;\n padding: 0;\n background-color: var(--tempest-border);\n border: none;\n border-radius: var(--tempest-radius-full);\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n.dotActive {\n background-color: var(--tempest-primary);\n}\n\n.dot:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .track {\n transition: none;\n }\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Carousel.module.js","names":[],"sources":["../../../src/components/Carousel/Carousel.module.css"],"sourcesContent":[".root {\n position: relative;\n width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.root:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.viewport {\n overflow: hidden;\n border-radius: var(--tempest-radius-lg);\n}\n\n.track {\n display: flex;\n transition: transform var(--tempest-duration-
|
|
1
|
+
{"version":3,"file":"Carousel.module.js","names":[],"sources":["../../../src/components/Carousel/Carousel.module.css"],"sourcesContent":[".root {\n position: relative;\n width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.root:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.viewport {\n overflow: hidden;\n border-radius: var(--tempest-radius-lg);\n}\n\n.track {\n display: flex;\n transition: transform var(--tempest-duration-base) var(--tempest-ease-out);\n}\n\n.slide {\n flex: 0 0 100%;\n min-width: 0;\n}\n\n.arrow {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n background-color: var(--tempest-bg);\n border: 1px solid var(--tempest-border);\n border-radius: var(--tempest-radius-full);\n box-shadow: var(--tempest-shadow-md);\n color: var(--tempest-text);\n font-size: var(--tempest-text-xl);\n line-height: 1;\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n@media (hover: hover) and (pointer: fine) {\n .arrow:hover:not(:disabled) {\n background-color: var(--tempest-surface);\n }\n}\n\n.arrow:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n.arrow:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.prev {\n left: var(--tempest-space-2);\n}\n\n.next {\n right: var(--tempest-space-2);\n}\n\n.dots {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--tempest-space-2);\n margin-top: var(--tempest-space-3);\n}\n\n.dot {\n width: 0.5rem;\n height: 0.5rem;\n padding: 0;\n background-color: var(--tempest-border);\n border: none;\n border-radius: var(--tempest-radius-full);\n cursor: pointer;\n transition: var(--tempest-transition-color);\n}\n\n.dotActive {\n background-color: var(--tempest-primary);\n}\n\n.dot:focus-visible {\n outline: 2px solid var(--tempest-primary);\n outline-offset: 2px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .track {\n transition: none;\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
const e=require("../../utils/cn.cjs"),t=require("../CopyButton/CopyButton.cjs"),n=require("./tokenize.cjs"),r=require("./CodeBlock.module.cjs");let i=require("react"),a=require("react/jsx-runtime");function o({code:o,language:s,filename:c,showLineNumbers:l=!1,highlightLines:u,copyable:d=!0,maxHeight:f,wrap:p=!1,label:m,className:h,...g}){let _=(0,i.useMemo)(()=>o.replace(/^\n+/,``).replace(/\s+$/,``),[o]),v=(0,i.useMemo)(()=>n.tokenizeLines(_,s),[_,s]),y=n.resolveLanguage(s),b=(0,i.useMemo)(()=>new Set(u??[]),[u]),x=m??(c&&typeof c==`string`?`Código: ${c}`:`Bloco de código${y===`plain`?``:` em ${y}`}`),S=!!c||d;return(0,a.jsxs)(`div`,{className:e.cn(r.default.wrapper,h),...g,children:[S&&(0,a.jsxs)(`div`,{className:r.default.header,children:[(0,a.jsx)(`span`,{className:r.default.filename,children:c??(y===`plain`?``:y)}),d&&(0,a.jsx)(t.CopyButton,{value:_,className:r.default.copy})]}),(0,a.jsx)(`pre`,{className:e.cn(r.default.pre,p&&r.default.wrap),style:{maxHeight:f},tabIndex:0,role:`group`,"aria-label":x,children:(0,a.jsx)(`code`,{className:r.default.code,"data-language":y,children:v.map((t,n)=>(0,a.jsxs)(i.Fragment,{children:[(0,a.jsxs)(`span`,{className:e.cn(r.default.line,b.has(n+1)&&r.default.marked),children:[l&&(0,a.jsx)(`span`,{className:r.default.lineNumber,"aria-hidden":`true`,children:n+1}),(0,a.jsx)(`span`,{className:r.default.lineContent,children:t.map((e,t)=>(0,a.jsx)(`span`,{className:r.default[e.kind],"data-token":e.kind,children:e.value},t))})]}),n<v.length-1?`
|
|
2
|
+
`:null]},n))})})]})}exports.CodeBlock=o;
|
|
3
|
+
//# sourceMappingURL=CodeBlock.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodeBlock.cjs","names":[],"sources":["../../../src/components/CodeBlock/CodeBlock.tsx"],"sourcesContent":["import { Fragment, useMemo } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\n\nimport { cn } from \"@/utils/cn\";\n\nimport { CopyButton } from \"../CopyButton\";\nimport { resolveLanguage, tokenizeLines } from \"./tokenize\";\nimport styles from \"./CodeBlock.module.css\";\n\nexport interface CodeBlockProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** The source to display. Leading and trailing blank lines are trimmed. */\n code: string;\n /** Grammar name or alias (`ts`, `bash`, `json`…). Unknown values render plain. */\n language?: string;\n /** Shown in the header, usually a file path. */\n filename?: ReactNode;\n /** Number the lines. Default `false`. */\n showLineNumbers?: boolean;\n /** 1-based line numbers to mark as the point of the snippet. */\n highlightLines?: readonly number[];\n /** Offer a copy button. Default `true`. */\n copyable?: boolean;\n /** Cap the height in px or any CSS length; the body scrolls past it. */\n maxHeight?: number | string;\n /** Wrap long lines instead of scrolling sideways. Default `false`. */\n wrap?: boolean;\n /**\n * Accessible name for the code region. Defaults to naming the language, and\n * to the filename when there is one.\n */\n label?: string;\n}\n\n/**\n * A read-only code sample: syntax colours, optional line numbers, copy button.\n *\n * The `<pre>` is always focusable. A code block is scrollable and holds nothing\n * focusable inside, so without a tab stop a keyboard user can see there is more\n * code past the edge and has no way to reach it. It is the one scroll container\n * where the stop is unconditional rather than measured — a code sample is\n * expected to be reachable, read and selected on its own.\n *\n * Colours come from an approximate scanner, not a parser — see {@link tokenize}.\n *\n * @example\n * <CodeBlock code={snippet} language=\"ts\" filename=\"src/main.ts\" showLineNumbers />\n * <CodeBlock code={log} language=\"bash\" maxHeight={280} />\n */\nexport function CodeBlock({\n code,\n language,\n filename,\n showLineNumbers = false,\n highlightLines,\n copyable = true,\n maxHeight,\n wrap = false,\n label,\n className,\n ...rest\n}: CodeBlockProps) {\n const trimmed = useMemo(() => code.replace(/^\\n+/, \"\").replace(/\\s+$/, \"\"), [code]);\n const lines = useMemo(() => tokenizeLines(trimmed, language), [trimmed, language]);\n const resolved = resolveLanguage(language);\n const marked = useMemo(() => new Set(highlightLines ?? []), [highlightLines]);\n\n const name =\n label ??\n (filename && typeof filename === \"string\"\n ? `Código: ${filename}`\n : `Bloco de código${resolved === \"plain\" ? \"\" : ` em ${resolved}`}`);\n\n const hasHeader = Boolean(filename) || copyable;\n\n return (\n <div className={cn(styles.wrapper, className)} {...rest}>\n {hasHeader && (\n <div className={styles.header}>\n <span className={styles.filename}>\n {filename ?? (resolved === \"plain\" ? \"\" : resolved)}\n </span>\n {copyable && <CopyButton value={trimmed} className={styles.copy} />}\n </div>\n )}\n\n <pre\n className={cn(styles.pre, wrap && styles.wrap)}\n style={{ maxHeight }}\n tabIndex={0}\n role=\"group\"\n aria-label={name}\n >\n <code className={styles.code} data-language={resolved}>\n {lines.map((tokens, index) => (\n <Fragment key={index}>\n <span\n className={cn(styles.line, marked.has(index + 1) && styles.marked)}\n >\n {showLineNumbers && (\n /*\n * The number is decoration: it must not land in the\n * clipboard when the reader selects the snippet, and a\n * screen reader announcing \"one const two import\" adds\n * nothing. `user-select: none` in CSS plus this.\n */\n <span className={styles.lineNumber} aria-hidden=\"true\">\n {index + 1}\n </span>\n )}\n <span className={styles.lineContent}>\n {tokens.map((token, tokenIndex) => (\n <span\n key={tokenIndex}\n className={styles[token.kind]}\n data-token={token.kind}\n >\n {token.value}\n </span>\n ))}\n </span>\n </span>\n {/*\n * A real newline character, and outside the line box.\n * It has to be real so that selecting the snippet by\n * hand and copying yields the source instead of one\n * run-together line. It has to be outside because the\n * line is an inline-block: a newline within one is\n * consumed inside that box, and every line ends up\n * side by side on a single row. The last one is\n * dropped so the block does not end in blank space.\n */}\n {index < lines.length - 1 ? \"\\n\" : null}\n </Fragment>\n ))}\n </code>\n </pre>\n </div>\n );\n}\n"],"mappings":"sMAgDA,SAAgB,EAAU,CACtB,OACA,WACA,WACA,kBAAkB,GAClB,iBACA,WAAW,GACX,YACA,OAAO,GACP,QACA,YACA,GAAG,GACY,CACf,IAAM,GAAA,EAAA,EAAA,QAAA,KAAwB,EAAK,QAAQ,OAAQ,EAAE,CAAC,CAAC,QAAQ,OAAQ,EAAE,EAAG,CAAC,CAAI,CAAC,EAC5E,GAAA,EAAA,EAAA,QAAA,KAAsB,EAAA,cAAc,EAAS,CAAQ,EAAG,CAAC,EAAS,CAAQ,CAAC,EAC3E,EAAW,EAAA,gBAAgB,CAAQ,EACnC,GAAA,EAAA,EAAA,QAAA,KAAuB,IAAI,IAAI,GAAkB,CAAC,CAAC,EAAG,CAAC,CAAc,CAAC,EAEtE,EACF,IACC,GAAY,OAAO,GAAa,SAC3B,WAAW,IACX,kBAAkB,IAAa,QAAU,GAAK,OAAO,OAEzD,EAAY,EAAQ,GAAa,EAEvC,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,CAAS,EAAG,GAAI,WAAnD,CACK,IACG,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,gBAAvB,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,kBACnB,IAAa,IAAa,QAAU,GAAK,EACxC,CAAA,EACL,IAAY,EAAA,EAAA,IAAA,CAAC,EAAA,WAAD,CAAY,MAAO,EAAS,UAAW,EAAA,QAAO,IAAO,CAAA,CACjE,KAGT,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,IAAK,GAAQ,EAAA,QAAO,IAAI,EAC7C,MAAO,CAAE,WAAU,EACnB,SAAU,EACV,KAAK,QACL,aAAY,YAEZ,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,KAAM,gBAAe,WACxC,EAAM,KAAK,EAAQ,KAChB,EAAA,EAAA,KAAA,CAAC,EAAA,SAAD,CAAA,SAAA,EACI,EAAA,EAAA,KAAA,CAAC,OAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,EAAO,IAAI,EAAQ,CAAC,GAAK,EAAA,QAAO,MAAM,WADrE,CAGK,IAOG,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,WAAY,cAAY,gBAC3C,EAAQ,CACP,CAAA,GAEV,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,qBACnB,EAAO,KAAK,EAAO,KAChB,EAAA,EAAA,IAAA,CAAC,OAAD,CAEI,UAAW,EAAA,QAAO,EAAM,MACxB,aAAY,EAAM,cAEjB,EAAM,KACL,EALG,CAKH,CACT,CACC,CAAA,CACJ,IAWL,EAAQ,EAAM,OAAS,EAAI;EAAO,IAC7B,CAAA,EAtCK,CAsCL,CACb,CACC,CAAA,CACL,CAAA,CACJ,GAEb"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { cn as e } from "../../utils/cn.js";
|
|
2
|
+
import { CopyButton as t } from "../CopyButton/CopyButton.js";
|
|
3
|
+
import { resolveLanguage as n, tokenizeLines as r } from "./tokenize.js";
|
|
4
|
+
import i from "./CodeBlock.module.js";
|
|
5
|
+
import { Fragment as a, useMemo as o } from "react";
|
|
6
|
+
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
7
|
+
//#region src/components/CodeBlock/CodeBlock.tsx
|
|
8
|
+
function l({ code: l, language: u, filename: d, showLineNumbers: f = !1, highlightLines: p, copyable: m = !0, maxHeight: h, wrap: g = !1, label: _, className: v, ...y }) {
|
|
9
|
+
let b = o(() => l.replace(/^\n+/, "").replace(/\s+$/, ""), [l]), x = o(() => r(b, u), [b, u]), S = n(u), C = o(() => new Set(p ?? []), [p]), w = _ ?? (d && typeof d == "string" ? `Código: ${d}` : `Bloco de código${S === "plain" ? "" : ` em ${S}`}`), T = !!d || m;
|
|
10
|
+
return /* @__PURE__ */ c("div", {
|
|
11
|
+
className: e(i.wrapper, v),
|
|
12
|
+
...y,
|
|
13
|
+
children: [T && /* @__PURE__ */ c("div", {
|
|
14
|
+
className: i.header,
|
|
15
|
+
children: [/* @__PURE__ */ s("span", {
|
|
16
|
+
className: i.filename,
|
|
17
|
+
children: d ?? (S === "plain" ? "" : S)
|
|
18
|
+
}), m && /* @__PURE__ */ s(t, {
|
|
19
|
+
value: b,
|
|
20
|
+
className: i.copy
|
|
21
|
+
})]
|
|
22
|
+
}), /* @__PURE__ */ s("pre", {
|
|
23
|
+
className: e(i.pre, g && i.wrap),
|
|
24
|
+
style: { maxHeight: h },
|
|
25
|
+
tabIndex: 0,
|
|
26
|
+
role: "group",
|
|
27
|
+
"aria-label": w,
|
|
28
|
+
children: /* @__PURE__ */ s("code", {
|
|
29
|
+
className: i.code,
|
|
30
|
+
"data-language": S,
|
|
31
|
+
children: x.map((t, n) => /* @__PURE__ */ c(a, { children: [/* @__PURE__ */ c("span", {
|
|
32
|
+
className: e(i.line, C.has(n + 1) && i.marked),
|
|
33
|
+
children: [f && /* @__PURE__ */ s("span", {
|
|
34
|
+
className: i.lineNumber,
|
|
35
|
+
"aria-hidden": "true",
|
|
36
|
+
children: n + 1
|
|
37
|
+
}), /* @__PURE__ */ s("span", {
|
|
38
|
+
className: i.lineContent,
|
|
39
|
+
children: t.map((e, t) => /* @__PURE__ */ s("span", {
|
|
40
|
+
className: i[e.kind],
|
|
41
|
+
"data-token": e.kind,
|
|
42
|
+
children: e.value
|
|
43
|
+
}, t))
|
|
44
|
+
})]
|
|
45
|
+
}), n < x.length - 1 ? "\n" : null] }, n))
|
|
46
|
+
})
|
|
47
|
+
})]
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { l as CodeBlock };
|
|
52
|
+
|
|
53
|
+
//# sourceMappingURL=CodeBlock.js.map
|