📝 docs(code-reader): useState 状态卡片原型的解构表改成 第几项 | 名称 | 说明 | 操作
This commit is contained in:
1 parent
719453a28b
commit
966d893f18
5 files changed
+2321
-1760
No files matched your search
Binary file not shown.
|
Before Width: | Height: | Size: 775 KiB After Width: | Height: | Size: 777 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 268 KiB After Width: | Height: | Size: 271 KiB |
+7
-3
@@ -645,13 +645,15 @@ function nameProp(ctx, name, color, tags, label) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表格:`cols` 是 `{name, color?, mono?}`,最后一列分剩下的;格子是着色的段、字符串(按列色)或带 `draw` 的对象。
|
* 表格:`cols` 是 `{name, color?, mono?, width?, fill?}`;格子是着色的段、字符串(按列色)或带 `draw` 的对象。
|
||||||
* 列宽按整列的内容估,表头浅底,行和列之间一条分隔线。
|
* 列宽按整列的内容估,给了 `width` 就用它;剩下的宽度归 `fill` 那一列,没有就归最后一列。表头浅底,行和列之间一条分隔线。
|
||||||
*/
|
*/
|
||||||
function table(ctx, cols, rows) {
|
function table(ctx, cols, rows) {
|
||||||
const tableW = ctx.w - 5;
|
const tableW = ctx.w - 5;
|
||||||
const cellText = (cell) => typeof cell === "string" ? cell : Array.isArray(cell) ? cell.map((s) => s.text).join("") : (cell.est || "");
|
const cellText = (cell) => typeof cell === "string" ? cell : Array.isArray(cell) ? cell.map((s) => s.text).join("") : (cell.est || "");
|
||||||
const natural = cols.map((c, i) => {
|
const natural = cols.map((c, i) => {
|
||||||
|
if (c.width)
|
||||||
|
return c.width;
|
||||||
let wMax = widthOf(c.name, 12, false);
|
let wMax = widthOf(c.name, 12, false);
|
||||||
for (const r of rows) wMax = Math.max(wMax, widthOf(cellText(r[i]), 12.5, c.mono !== false) + (r[i] && r[i].extra ? r[i].extra : 0));
|
for (const r of rows) wMax = Math.max(wMax, widthOf(cellText(r[i]), 12.5, c.mono !== false) + (r[i] && r[i].extra ? r[i].extra : 0));
|
||||||
return Math.ceil(wMax + 18);
|
return Math.ceil(wMax + 18);
|
||||||
@@ -659,7 +661,9 @@ function table(ctx, cols, rows) {
|
|||||||
const last = cols.length - 1;
|
const last = cols.length - 1;
|
||||||
const avail = tableW - 2 - last;
|
const avail = tableW - 2 - last;
|
||||||
const widths = natural.slice();
|
const widths = natural.slice();
|
||||||
widths[last] = avail - widths.slice(0, last).reduce((a, b) => a + b, 0);
|
const fill = cols.findIndex((c) => c.fill);
|
||||||
|
const flex = fill >= 0 ? fill : last;
|
||||||
|
widths[flex] = avail - widths.reduce((sum, wd, i) => (i === flex ? sum : sum + wd), 0);
|
||||||
const outer = col(ctx.content, "Table wrap", { padding: [2, 0, 2, 5] });
|
const outer = col(ctx.content, "Table wrap", { padding: [2, 0, 2, 5] });
|
||||||
const grid = col(outer, "Table", { radius: 4, stroke: C.borderStrong, clip: true });
|
const grid = col(outer, "Table", { radius: 4, stroke: C.borderStrong, clip: true });
|
||||||
const headBg = mix("#ffffff", ctx.bg, 0.05);
|
const headBg = mix("#ffffff", ctx.bg, 0.05);
|
||||||
|
|||||||
+45
-19
@@ -1,6 +1,7 @@
|
|||||||
// 代码阅读 React 状态卡片:useState 不再写成「钩子 useState」,而是一张「状态」卡片,讲清楚五件事:
|
// 代码阅读 React 状态卡片:useState 不再写成「钩子 useState」,而是一张「状态」卡片,讲清楚五件事:
|
||||||
// 它是普通变量也是 React 状态(左边变量、状态两个图标);它是数组解构(名称照源码写出解构,展开是每一项);
|
// 它是普通变量也是 React 状态(左边变量、状态两个图标);它是数组解构(名称照源码写出解构,展开是每一项);
|
||||||
// 它来自 React 内置的 useState(悬停说明);状态类型;默认值。解构出的每一项各有一个调用树按钮:当前值查谁用了它,修改函数查谁改了它。
|
// 它来自 React 内置的 useState(悬停说明);状态类型;默认值。解构表的「操作」一列放每一项能做的操作,
|
||||||
|
// 现在是调用树:当前值查谁用了它,修改函数查谁改了它。
|
||||||
// 画板一照抄 luffy-agent-platform 的 frontend/client-nextjs/src/app/desktop/login/page.tsx 第 1–37 行,
|
// 画板一照抄 luffy-agent-platform 的 frontend/client-nextjs/src/app/desktop/login/page.tsx 第 1–37 行,
|
||||||
// 画板二是手写的三行,讲没标类型、函数形式的默认值、只取当前值三种写法。
|
// 画板二是手写的三行,讲没标类型、函数形式的默认值、只取当前值三种写法。
|
||||||
// 窗口、对齐、别的卡片的画法在同目录 react-shared.js,接在它后面跑:`cat react-shared.js react-state.js | op design - --script`。
|
// 窗口、对齐、别的卡片的画法在同目录 react-shared.js,接在它后面跑:`cat react-shared.js react-state.js | op design - --script`。
|
||||||
@@ -85,35 +86,51 @@ const VARIANTS = sampleFile({
|
|||||||
// 种类「状态」:描边、淡底、两个图标都用变量色;左边先是变量卡片的图标,再是状态图标,悬停才出名字
|
// 种类「状态」:描边、淡底、两个图标都用变量色;左边先是变量卡片的图标,再是状态图标,悬停才出名字
|
||||||
const STATE = { label: "状态", color: "#9cdcfe", icon: "variable" };
|
const STATE = { label: "状态", color: "#9cdcfe", icon: "variable" };
|
||||||
|
|
||||||
// 解构出的每一项:是什么、它那一行调用树按钮查什么(悬停文字)
|
// 解构出的每一项:说明、它那一行调用树按钮查什么(悬停文字)
|
||||||
const ITEMS = [
|
const ITEMS = [
|
||||||
{ what: "当前值", tip: "谁用了这个状态" },
|
{ what: "当前值", tip: "谁用了这个状态" },
|
||||||
{ what: "修改函数", tip: "谁改了这个状态" },
|
{ what: "修改函数", tip: "谁改了这个状态" },
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/** 一个调用树按钮的宽度,同 [callTreeButton]:有次数时图标加小圆标,0 次只有图标。 */
|
||||||
* 「是什么」一格:说法后面跟这一项自己的调用树按钮,`calls` 是它在样例里出现几次;
|
function callTreeWidth(calls) {
|
||||||
* `bubble` 时按钮右边画出它的悬停气泡(上方是上一行的按钮,放上面会挡住它)。
|
return calls === 0 ? 22 : 4 + 14 + 1 + 14 + 4;
|
||||||
*/
|
}
|
||||||
function whatCell(item, calls, bubble) {
|
|
||||||
|
/** 「操作」一格:这一项能做的操作从左往右排,现在只有调用树。 */
|
||||||
|
function opsCell(item, calls) {
|
||||||
return {
|
return {
|
||||||
est: item.what,
|
est: "",
|
||||||
extra: 6 + 37,
|
|
||||||
draw: (frame) => {
|
draw: (frame) => {
|
||||||
const line = row(frame, "What", { gap: 6, height: 20, width: "fit_content" });
|
const line = row(frame, "Ops", { gap: 2, height: 20, width: "fit_content" });
|
||||||
text(line, item.what, { size: 12.5, lh: 20 });
|
|
||||||
callTreeButton(line, calls, item.tip);
|
callTreeButton(line, calls, item.tip);
|
||||||
if (bubble)
|
|
||||||
tooltip(line, item.tip);
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 一处 useState:名称照源码写出解构(后面灰字「数组解构」,展开是「第几项 | 名称 | 是什么」,每一项一个调用树按钮)/
|
* 第 `n` 行调用树按钮的悬停气泡在卡片里的位置:在按钮正下方居中、隔 6px。
|
||||||
|
* 按钮上方是上一行的按钮,右边伸出卡片,只有下面空着(「来自」那一行的右半边)。
|
||||||
|
* 卡片里的位置照 [card]、[table] 的排法算:内容区左边在 84px(内边距 8、折叠箭头 14、两个图标 42、两处间距 10),
|
||||||
|
* 宽是卡片宽减 150;表从内容区上方 8 + 名称一行 20 + 间距 3 处开始,表格框留白 2、表头 24、每行前面 1px 分隔线、行高 24,
|
||||||
|
* 一行的各格从表格框左边 5px 排到内容区右边往回 2px,「操作」一格在最右,按钮在格子左边 8px、上边 2px。
|
||||||
|
*/
|
||||||
|
function opsBubble(w, n, opsW, calls, tip) {
|
||||||
|
const contentX = 8 + 14 + 10 + 42 + 10;
|
||||||
|
const rowEnd = contentX + (w - 150) - 2;
|
||||||
|
const rowTop = 8 + 20 + 3 + 2 + 24 + (n - 1) * 25 + 1;
|
||||||
|
const buttonX = rowEnd - opsW + 8;
|
||||||
|
const buttonBottom = rowTop + 2 + 20;
|
||||||
|
return { x: buttonX + callTreeWidth(calls) / 2 - tooltipWidth(tip) / 2, y: buttonBottom + 6 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一处 useState:名称照源码写出解构(后面灰字「数组解构」,展开是「第几项 | 名称 | 说明 | 操作」)/
|
||||||
* 来自(悬停说是 React 内置钩子)/ 状态类型 / 默认值。
|
* 来自(悬停说是 React 内置钩子)/ 状态类型 / 默认值。
|
||||||
* `names` 是解构出的名字,第二个是修改函数;`calls` 是各项在样例里出现几次。
|
* `names` 是解构出的名字,第二个是修改函数;`calls` 是各项在样例里出现几次,「操作」一格里调用树按钮上的数字。
|
||||||
* `type` 是状态类型(没写时「未标注」),`initial` 是默认值的着色段;`bubble` 画出修改函数那一行调用树按钮的悬停气泡。
|
* 「操作」一列按这张卡里按钮最宽的那一行定宽(不窄于表头),「说明」一列分剩下的。
|
||||||
|
* `type` 是状态类型(没写时「未标注」),`initial` 是默认值的着色段。
|
||||||
|
* `bubble` 画出修改函数那一行调用树按钮的悬停气泡:卡片和气泡放进一个自由摆放的框,气泡在前,才画在卡片上层。
|
||||||
*/
|
*/
|
||||||
function stateCard(s) {
|
function stateCard(s) {
|
||||||
return (parent, w) => {
|
return (parent, w) => {
|
||||||
@@ -121,7 +138,16 @@ function stateCard(s) {
|
|||||||
{ name: "variable", color: STATE.color, tip: "变量" },
|
{ name: "variable", color: STATE.color, tip: "变量" },
|
||||||
{ name: "toggle-right", color: STATE.color, tip: "React 状态" },
|
{ name: "toggle-right", color: STATE.color, tip: "React 状态" },
|
||||||
];
|
];
|
||||||
const ctx = card(parent, STATE, w, { name: s.names[0], icons });
|
const opsW = Math.max(Math.ceil(widthOf("操作", 12, false) + 18), 8 + Math.max(...s.calls.map(callTreeWidth)) + 8);
|
||||||
|
let holder = parent;
|
||||||
|
let place = {};
|
||||||
|
if (s.bubble) {
|
||||||
|
holder = box(parent, "Hover / 谁改了这个状态", { layout: "none", width: w, height: "fit_content" });
|
||||||
|
const spot = opsBubble(w, 2, opsW, s.calls[1], ITEMS[1].tip);
|
||||||
|
tooltip(holder, ITEMS[1].tip, spot.x, spot.y);
|
||||||
|
place = { x: 0, y: 0 };
|
||||||
|
}
|
||||||
|
const ctx = card(holder, STATE, w, Object.assign({ name: s.names[0], icons }, place));
|
||||||
prop(ctx, "名称", (frame) => {
|
prop(ctx, "名称", (frame) => {
|
||||||
const line = row(frame, "Destructure", { gap: 8, height: 20, width: "fit_content" });
|
const line = row(frame, "Destructure", { gap: 8, height: 20, width: "fit_content" });
|
||||||
const parts = [seg("[", C.fg)];
|
const parts = [seg("[", C.fg)];
|
||||||
@@ -134,8 +160,8 @@ function stateCard(s) {
|
|||||||
text(line, parts, { mono: true });
|
text(line, parts, { mono: true });
|
||||||
text(line, "数组解构", { size: 12.5, color: C.desc });
|
text(line, "数组解构", { size: 12.5, color: C.desc });
|
||||||
}, { fold: "open" });
|
}, { fold: "open" });
|
||||||
table(ctx, [{ name: "第几项", mono: false }, { name: "名称", color: C.variable }, { name: "是什么", mono: false }],
|
table(ctx, [{ name: "第几项", mono: false }, { name: "名称", color: C.variable }, { name: "说明", mono: false, fill: true }, { name: "操作", width: opsW }],
|
||||||
s.names.map((name, i) => [indexCell(i + 1), px(name, i === 0 ? C.variable : C.fn), whatCell(ITEMS[i], s.calls[i], s.bubble && i === 1)]));
|
s.names.map((name, i) => [indexCell(i + 1), px(name, i === 0 ? C.variable : C.fn), ITEMS[i].what, opsCell(ITEMS[i], s.calls[i])]));
|
||||||
prop(ctx, "来自", (frame) => text(frame, px("useState", C.fn), { mono: true, name: "useState(悬停:React 内置钩子)" }));
|
prop(ctx, "来自", (frame) => text(frame, px("useState", C.fn), { mono: true, name: "useState(悬停:React 内置钩子)" }));
|
||||||
prop(ctx, "状态类型", s.type || px("未标注", C.desc), { mono: Boolean(s.type) });
|
prop(ctx, "状态类型", s.type || px("未标注", C.desc), { mono: Boolean(s.type) });
|
||||||
prop(ctx, "默认值", s.initial);
|
prop(ctx, "默认值", s.initial);
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user