Give Markdown blocks one consistent gap, roomier on desktop, and a zoom-in cursor on images (#7298)

* fix(scripts): recover installs when a dependency patch changed

patch-package cannot apply a patch over a package patched with an earlier
version of it, and without --error-on-fail it exits 0 locally. Checkouts kept
the stale patch silently: the Markdown code block spacing fix never reached
them. The script now fails the install and removes that package so the next
npm install reinstalls it clean with the current patch. A patch-package that
cannot start fails the install without removing anything.

* fix(app): give Markdown blocks one gap and roomier desktop spacing

Every Markdown block is followed by one gap, density.blockGap: 12 on compact
layouts and 16 wider. The library's element styles and the views stacked
outside it (Mermaid segments on native, streaming head and tail) take the same
token, so no block type carries its own margins. Desktop was too tight at 12.

Markdown images show a zoom-in cursor on web, since tapping opens the lightbox.
This commit is contained in:
Mohamed Boudra
2026-10-18 15:12:28 +07:00
committed by GitHub
parent 3882b957a6
commit 233997ed5c
15 changed files with 245 additions and 136 deletions
+27 -23
View File
@@ -60,30 +60,37 @@ if (!existsSync("patches") || installedPackages.length === 0) {
const patchFiles = readdirSync("patches").filter((file) => file.endsWith(".patch"));
// Group patch files by the directory patch-package must run from.
const patchFilesByCwd = new Map();
for (const { patchPrefix, cwd = "." } of installedPackages) {
const isWindows = process.platform === "win32";
const cmd = isWindows ? "patch-package.cmd" : "patch-package";
let failed = false;
for (const [index, { nodeModulesPath, patchPrefix, cwd = "." }] of installedPackages.entries()) {
const files = patchFiles.filter((file) => file.startsWith(patchPrefix));
if (files.length === 0) {
continue;
}
const group = patchFilesByCwd.get(cwd) ?? [];
group.push(...files);
patchFilesByCwd.set(cwd, group);
const outcome = applyPatches(cwd, files, index);
if (outcome === "applied") {
continue;
}
failed = true;
if (outcome === "unavailable") {
continue;
}
// patch-package cannot apply a patch that changed after an earlier version of it was
// applied. Without the package, the next install fetches it clean and applies the patch.
rmSync(nodeModulesPath, { recursive: true, force: true });
console.error(
`postinstall-patches: removed ${nodeModulesPath} because its patch did not apply. ` +
"Run npm install again to reinstall it with the current patch. " +
"If it fails again on the clean package, the patch is out of date and must be regenerated.",
);
}
if (patchFilesByCwd.size === 0) {
process.exit(0);
}
const isWindows = process.platform === "win32";
const cmd = isWindows ? "patch-package.cmd" : "patch-package";
let groupIndex = 0;
for (const [cwd, files] of patchFilesByCwd) {
groupIndex += 1;
const tempPatchDir = join(".tmp", `postinstall-patches-${process.pid}-${groupIndex}`);
process.exit(failed ? 1 : 0);
function applyPatches(cwd, files, index) {
const tempPatchDir = join(".tmp", `postinstall-patches-${process.pid}-${index}`);
mkdirSync(tempPatchDir, { recursive: true });
for (const patchFile of files) {
copyFileSync(join("patches", patchFile), join(tempPatchDir, patchFile));
@@ -91,7 +98,7 @@ for (const [cwd, files] of patchFilesByCwd) {
let result;
try {
result = spawnSync(cmd, ["--patch-dir", relative(cwd, tempPatchDir)], {
result = spawnSync(cmd, ["--patch-dir", relative(cwd, tempPatchDir), "--error-on-fail"], {
cwd,
shell: isWindows,
stdio: "inherit",
@@ -103,10 +110,7 @@ for (const [cwd, files] of patchFilesByCwd) {
if (result.error) {
console.error("postinstall-patches: patch-package failed to spawn:", result.error.message);
return "unavailable";
}
if (result.status !== 0) {
process.exit(result.status ?? 1);
}
return result.status === 0 ? "applied" : "rejected";
}
process.exit(0);
+99
View File
@@ -0,0 +1,99 @@
import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { test } from "node:test";
const script = path.resolve("scripts", "postinstall-patches.mjs");
const bin = path.resolve("node_modules", ".bin");
const packageName = "react-native-draggable-flatlist";
const patchFile = `${packageName}+4.0.3.patch`;
function createCheckout() {
const root = mkdtempSync(path.join(tmpdir(), "postinstall-patches-"));
writeFileSync(path.join(root, "package.json"), JSON.stringify({ name: "checkout" }));
const packageDir = path.join(root, "node_modules", packageName);
mkdirSync(packageDir, { recursive: true });
writeFileSync(
path.join(packageDir, "package.json"),
JSON.stringify({ name: packageName, version: "4.0.3" }),
);
writeFileSync(path.join(packageDir, "index.js"), "export const value = 1;\n");
mkdirSync(path.join(root, "patches"));
return { root, packageDir };
}
function writePatch(root, from, to) {
const file = `node_modules/${packageName}/index.js`;
writeFileSync(
path.join(root, "patches", patchFile),
[
`diff --git a/${file} b/${file}`,
`--- a/${file}`,
`+++ b/${file}`,
"@@ -1 +1 @@",
`-export const value = ${from};`,
`+export const value = ${to};`,
"",
].join("\n"),
);
}
function install(root, PATH = `${bin}${path.delimiter}${process.env.PATH}`) {
return spawnSync(process.execPath, [script], {
cwd: root,
encoding: "utf8",
env: { ...process.env, PATH },
});
}
test("a patch that changed since it was applied removes the package for a clean reinstall", () => {
const { root, packageDir } = createCheckout();
try {
writePatch(root, 1, 2);
assert.equal(install(root).status, 0);
assert.equal(
readFileSync(path.join(packageDir, "index.js"), "utf8"),
"export const value = 2;\n",
);
writePatch(root, 1, 3);
const result = install(root);
assert.equal(result.status, 1);
assert.match(result.stderr, /Run npm install again/);
assert.equal(existsSync(packageDir), false);
} finally {
rmSync(root, { recursive: true, force: true });
}
});
test("an already applied patch leaves the package in place", () => {
const { root, packageDir } = createCheckout();
try {
writePatch(root, 1, 2);
assert.equal(install(root).status, 0);
assert.equal(install(root).status, 0);
assert.equal(
readFileSync(path.join(packageDir, "index.js"), "utf8"),
"export const value = 2;\n",
);
} finally {
rmSync(root, { recursive: true, force: true });
}
});
test("a missing patch-package fails the install and leaves the package in place", () => {
const { root, packageDir } = createCheckout();
try {
writePatch(root, 1, 2);
const result = install(root, root);
assert.equal(result.status, 1);
assert.match(result.stderr, /failed to spawn/);
assert.equal(existsSync(packageDir), true);
} finally {
rmSync(root, { recursive: true, force: true });
}
});