feat: 等比多尺寸适配#3457
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
Walkthrough新增运行时缩放工具(scale-f)、构建时 SCSS px->scale-px 转换器并集成到构建脚本、在全局样式中添加缩放函数与大量设计令牌替换,迁移并调整 40+ 组件样式与若干渲染代码,应用入口与 demo 集成初始化,并添加技能文档与白皮书微调。 ChangesNutUI React 等比适配系统
Estimated code review effort 🎯 4 (Complex) | ⏱️ ~60 分钟 Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/packages/avatarcropper/avatarcropper.taro.tsx (1)
141-153:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift修复 useLayoutEffect 中的闭包陷阱和时序风险。
闭包问题(确认):第 149 行使用
setCanvasAll({ ...canvasAll, cropperCanvas: canvas })中的canvasAll,但它不在第 153 行的依赖数组[showAlipayCanvas2D, state.displayHeight, state.displayWidth]中,导致读取过期状态。改用函数式更新避免:setCanvasAll(prev => ({ ...prev, cropperCanvas: canvas }))生命周期不一致:项目中其他需要 DOM 查询的组件(如
swipe.taro.tsx、range.taro.tsx)均采用useReady+nextTick模式,并有明确注释说明"需要参考小程序的事件周期"。avatarcropper 使用useLayoutEffect存在与小程序生命周期不匹配的风险,特别是支付宝小程序的 Canvas2D 初始化时序更为敏感。建议改用
useReady+nextTick的标准模式,或至少补充nextTick确保 DOM 就绪。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/packages/avatarcropper/avatarcropper.taro.tsx` around lines 141 - 153, The effect uses a stale closure over canvasAll and runs in useLayoutEffect which can mismatch the mini-program lifecycle; change setCanvasAll({ ...canvasAll, cropperCanvas: canvas }) to a functional updater setCanvasAll(prev => ({ ...prev, cropperCanvas: canvas })) to avoid the closure bug, and replace (or wrap) the useLayoutEffect block that reads the DOM (showAlipayCanvas2D / createSelectorQuery / canvasId) with the mini-program pattern useReady + nextTick (or call nextTick before querying) so the canvas node is queried only after the platform DOM is reliably ready.src/packages/lottie/lottiemp.taro.tsx (1)
26-75:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
useLayoutEffect重跑时缺少清理,可能重复创建动画实例与事件监听。当前初始化逻辑会因依赖变化反复执行,但旧实例只在
useUnload时销毁,导致同一组件生命周期内可能出现实例/监听累积。建议修复(在 effect 内增加 cleanup)
useLayoutEffect(() => { + let disposed = false createSelectorQuery() .select(`#${id}`) .fields( { node: true, size: true, }, (res) => { + if (disposed) return try { const canvas = res.node const context = canvas.getContext('2d') @@ lottie.setup(canvas) animation.current = lottie.loadAnimation({ @@ inited.current = true } catch (error) { console.error(error) } } ) .exec() + + return () => { + disposed = true + if (onComplete && animation.current) { + animation.current.removeEventListener('complete', onComplete) + } + if (animation.current) { + animation.current.destroy() + animation.current = null + } + inited.current = false + } }, [autoPlay, dpr, id, loop, onComplete, source, speed, style])🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/packages/lottie/lottiemp.taro.tsx` around lines 26 - 75, The effect using useLayoutEffect (which calls lottie.loadAnimation and adds event listeners via animation.current.addEventListener) lacks a cleanup so repeated runs leak animation instances and listeners; update the effect to (1) before creating a new animation check if animation.current exists and call its removeEventListener (for the onComplete handler) and destroy method (or lottie.destroy on the instance) and null it, (2) store the onComplete handler reference so you can remove it reliably, and (3) return a cleanup function from useLayoutEffect that removes the event listener and destroys the current animation and sets inited.current/animation.current to false/null; target symbols: useLayoutEffect, animation.current, inited.current, lottie.loadAnimation, addEventListener/removeEventListener, and the onComplete handler.
🧹 Nitpick comments (7)
src/packages/searchbar/demos/h5/demo6.tsx (1)
18-20: ⚡ Quick win简化状态切换逻辑
当前的三元表达式可以简化为更简洁的布尔取反形式。
♻️ 建议的简化方案
<Popover visible={lightTheme} onClick={() => { - lightTheme ? setLightTheme(false) : setLightTheme(true) + setLightTheme(!lightTheme) }} list={itemList} >🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/packages/searchbar/demos/h5/demo6.tsx` around lines 18 - 20, 在 onClick 的处理器中,当前用三元表达式切换状态 (lightTheme ? setLightTheme(false) : setLightTheme(true)),请改为直接取反布尔值并传入 setLightTheme,例如在 onClick 回调中调用 setLightTheme(!lightTheme);定位到包含 lightTheme 和 setLightTheme 的 onClick 匿名函数并替换为布尔取反形式以简化逻辑。src/packages/timeselect/timeselect.scss (1)
16-16: ⚡ Quick win考虑移除或恢复注释掉的代码。
如果
width: $timeselect-date-width;不再需要,建议完全删除该行而不是注释掉。如果这是临时测试(考虑到 PR 标题"仅对比使用"),请在最终合并前明确处理。保留注释的代码会增加代码库的维护负担。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/packages/timeselect/timeselect.scss` at line 16, 在 src/packages/timeselect/timeselect.scss 中处理被注释的样式行 `width: $timeselect-date-width;`:如果该样式确实不再需要,直接删除这行;如果是临时注释用于对比/测试,则恢复该行并添加简短注释说明原因和何时可删除(或在 PR 合并前再确认);确保变量 `$timeselect-date-width` 在恢复时可用且样式不会引入布局回归。src/sites/mobile/main.tsx (1)
32-32: ⚡ Quick win建议为
initScaleF增加清理钩子,避免重复注册副作用Line [32] 当前直接调用
initScaleF('elderly')。建议保存返回的 disposer,并在 HMR dispose 阶段清理,避免开发态重复执行带来的监听叠加风险。可参考修改
if (rootElement != null) { - initScaleF('elderly') + const disposeScale = initScaleF('elderly') + if (import.meta.hot) { + import.meta.hot.dispose(() => { + disposeScale?.() + }) + } const root = ReactDOM.createRoot(rootElement) root.render(<App />) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/sites/mobile/main.tsx` at line 32, 当前直接调用 initScaleF('elderly') 会在开发态 HMR 多次执行时重复注册副作用;修改为保存 initScaleF 的返回值(比如 const disposeScale = initScaleF('elderly') 或类似变量),并在 HMR 卸载阶段调用该 disposer(在 import.meta.hot?.dispose(() => disposeScale?.()) 内清理)以避免监听/副作用叠加;确保在非 HMR 环境也能安全忽略或调用该 disposer。src/packages/tour/tour.scss (1)
32-33: ⚡ Quick win建议 close 图标尺寸改为缩放函数,保持与适配体系一致
Line [32]-[33] 建议避免固定
10px,改为scale-icon-px(10px),避免在大字版/等比适配下尺寸不一致。可参考修改
&-close { - width: 10px; - height: 10px; + width: scale-icon-px(10px); + height: scale-icon-px(10px); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/packages/tour/tour.scss` around lines 32 - 33, Replace the fixed 10px sizing for the close icon in src/packages/tour/tour.scss by using the scaling helper so it respects the adaptive system: change the width and height properties currently set to 10px to use scale-icon-px(10px) (i.e., width: scale-icon-px(10px); height: scale-icon-px(10px);) so the close icon sizing is consistent with the app's scaling system.src/utils/scale-f.ts (2)
226-242: 💤 Low value
options.scale校验可以更直接。
Number.isFinite(options.scale) && Number(options.scale) > 0 ? Number(options.scale) : scale这一段调用了 3 次Number(options.scale),可读性不佳。options.scale类型已经是number | undefined,可改成:简化建议
- const currentScale = - Number.isFinite(options.scale) && Number(options.scale) > 0 - ? Number(options.scale) - : scale + const overrideScale = options.scale + const currentScale = + typeof overrideScale === 'number' && + Number.isFinite(overrideScale) && + overrideScale > 0 + ? overrideScale + : scale🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/scale-f.ts` around lines 226 - 242, The scale validation in calcByProfile repeats Number(options.scale) three times; convert options.scale to a local numeric variable once (e.g., let s = options.scale as number | undefined; or const providedScale = options.scale) then coerce/validate that single value (Number or Number.isFinite and > 0) and use it as currentScale, falling back to the module-level scale; update calcByProfile to reference this single-local variable instead of calling Number(options.scale) multiple times.
178-188: 💤 Low value
!scale判断为冗余防御。
scale在模块顶层初始化为1,且setScaleF内部已通过Number.isFinite(nextScale) && nextScale > 0 ? nextScale : 1保证落库的值始终> 0。因此!scale永远为false,整个条件可以简化为nextScale !== scale。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/scale-f.ts` around lines 178 - 188, The condition in refreshScaleF contains a redundant defensive check "!scale" because scale is initialized to 1 and setScaleF already ensures stored values are > 0; remove the "!scale" part and simplify the if to only compare nextScale !== scale so the body calls setScaleF(nextScale) only when the fetched value differs; keep the existing profile-switching logic (setScaleProfile(nextProfile)) and the function return behavior unchanged.scripts/px-to-scale-px-in-component-scss.cjs (1)
31-54: 💤 Low value
findInnermostCalcRange命名与实际行为不符。函数注释也写明了"最左侧的「体内不含 calc(」的 calc 块"。实际返回的是最左侧的叶子 calc(body 内不再含
calc(),并不是 "innermost"。在外层有嵌套 calc 时容易让阅读者误以为是按深度优先寻找最内层。建议改名以匹配语义,例如findLeftmostLeafCalcRange:建议改名
-/** 最左侧的「体内不含 calc(」的 calc 块(同一层里先处理最左) */ -function findInnermostCalcRange(str) { +/** 同一层中最左侧的叶子 calc 块(体内不再含 calc()。 */ +function findLeftmostLeafCalcRange(str) { @@ - const m = findInnermostCalcRange(v) + const m = findLeftmostLeafCalcRange(v)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/px-to-scale-px-in-component-scss.cjs` around lines 31 - 54, The function name findInnermostCalcRange is misleading because it actually finds the leftmost leaf calc (a calc(...) whose body does not contain another calc), so rename the function to findLeftmostLeafCalcRange and update its comment accordingly; update every reference/usage of findInnermostCalcRange in this module to the new name (e.g., callers that expect the "innermost" behavior), and run/adjust any tests or examples that mention findInnermostCalcRange to reflect the new identifier.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/px-to-scale-px-in-component-scss.cjs`:
- Line 16: The script's PROP_SKIP constant currently lists font-size exceptions
but lacks documentation about how demo files are treated relative to the
SKILL.md constraint; update the top-of-file comment in the script (near
PROP_SKIP) to state the SKILL.md 3.3 rule for "scale-font-px" vs theme tokens,
clarify that the script only transforms component SCSS (not demo files) unless
repo policy changes, and explicitly note the expected exemptions (e.g.,
skeleton's 0px) and recommended next steps: either exclude demo directories from
processing in this script or add a CI lint rule to enforce scaling in demos
and/or update SKILL.md to declare demos exempt.
In `@src/packages/inputnumber/inputnumber.scss`:
- Around line 26-27: The .nut-icon rules were changed to hardcoded sizes (10px /
16px) which breaks the global CSS variable scaling; restore usage of the global
CSS variables by replacing the hardcoded width and height in the .nut-icon
selector(s) with var(--nut-icon-width) and var(--nut-icon-height) so the
component respects --nut-scale-icon and matches radio/checkbox behavior (update
both small and default/large .nut-icon occurrences to use the variables).
In `@src/packages/searchbar/demos/h5/demo6.tsx`:
- Around line 24-29: The inline styles in the demo (the style object with
fontSize and width in src/packages/searchbar/demos/h5/demo6.tsx) use hard-coded
'12px' and '50px' which bypass the project's scaling CSS variables; update the
style to remove fixed px values or replace them with calc() using the scale
variable (e.g., calc(12px * var(--nut-scale-font))) or reference the appropriate
CSS variables so fontSize and width respect --nut-scale-font and other sizing
tokens; apply the same change to the corresponding style block in
src/packages/searchbar/demos/taro/demo6.tsx.
In `@src/packages/shortpassword/shortpassword.scss`:
- Line 13: The change incorrectly assigns a pixel font-size variable
($font-size-l) to line-height, causing semantic and spacing issues; update the
rule that sets line-height to use the unitless/design token $line-height-base
(or another dedicated line-height variable) instead of $font-size-l so that the
selector using line-height gets a proper proportional value; locate the line
containing "line-height: $font-size-l;" in
src/packages/shortpassword/shortpassword.scss and replace it with use of
$line-height-base (or a numeric unitless value like 1.5) to fix the semantics.
In `@src/packages/swipe/swipe.scss`:
- Line 35: 在包含注释文本 `//left: 100%;` 的位置前插入一个空行以修复
scss/double-slash-comment-empty-line-before lint 违规;也就是在 swipe.scss
中找到该注释并在其上一行添加一个空行,提交后 lint 应通过。
In `@src/styles/variables.scss`:
- Line 7: Several SCSS stylelint errors stem from missing empty lines before
double-slash section comments and from extraneous blank lines before the first
dollar-variable in variable groups; fix by ensuring there is exactly one blank
line immediately before section comments like "// ---- icon size ----" and by
removing the empty line that appears directly above the first $ variable in each
group (addresses rules scss/double-slash-comment-empty-line-before and
scss/dollar-variable-empty-line-before for the occurrences around the mentioned
comment and the $ variable blocks at the reported locations).
- Line 1353: The SCSS token $swiper-indicator-bottom is being assigned
unconditionally which overrides external presets; update the declaration of
$swiper-indicator-bottom to append !default (i.e., change the assignment so it
becomes a defaultable variable) so it can be overridden by consumers and remain
consistent with other tokens in the file.
- Around line 7-17: 移除未被使用的 CSS 变量
--nut-icon-height、--nut-icon-width、--nut-icon-line-height(当前在 :root 中带
!important 的三条定义),因为仓库实际使用的是 --nutui-icon-*
系列;在文件中删除这三条冗余变量定义以统一命名空间并避免维护负担;如果确实想保留兼容性可改名为 --nutui-icon-* 并验证与现有
scale-icon-px() 的回退逻辑(位于原文件的第 555–557 行)不会被破坏。
In `@src/utils/scale-f.ts`:
- Around line 190-205: The resize handler in initScaleF can cause high-frequency
concurrent refreshScaleF() calls (which await getScaleByNative()) and also
allows duplicate listeners; make initScaleF idempotent by storing a module-level
disposer and calling it at start to remove any existing listener before
registering a new one, debounce/coalesce resize events using
requestAnimationFrame (or a short timer) inside the handler to avoid rapid
concurrent calls, and implement a monotonically incremented token/version in
refreshScaleF/getScaleByNative flow so each async response compares its token
before writing CSS variables (drop outdated responses); ensure the same handler
reference is used for addEventListener/removeEventListener so the disposer
reliably removes the listener.
---
Outside diff comments:
In `@src/packages/avatarcropper/avatarcropper.taro.tsx`:
- Around line 141-153: The effect uses a stale closure over canvasAll and runs
in useLayoutEffect which can mismatch the mini-program lifecycle; change
setCanvasAll({ ...canvasAll, cropperCanvas: canvas }) to a functional updater
setCanvasAll(prev => ({ ...prev, cropperCanvas: canvas })) to avoid the closure
bug, and replace (or wrap) the useLayoutEffect block that reads the DOM
(showAlipayCanvas2D / createSelectorQuery / canvasId) with the mini-program
pattern useReady + nextTick (or call nextTick before querying) so the canvas
node is queried only after the platform DOM is reliably ready.
In `@src/packages/lottie/lottiemp.taro.tsx`:
- Around line 26-75: The effect using useLayoutEffect (which calls
lottie.loadAnimation and adds event listeners via
animation.current.addEventListener) lacks a cleanup so repeated runs leak
animation instances and listeners; update the effect to (1) before creating a
new animation check if animation.current exists and call its removeEventListener
(for the onComplete handler) and destroy method (or lottie.destroy on the
instance) and null it, (2) store the onComplete handler reference so you can
remove it reliably, and (3) return a cleanup function from useLayoutEffect that
removes the event listener and destroys the current animation and sets
inited.current/animation.current to false/null; target symbols: useLayoutEffect,
animation.current, inited.current, lottie.loadAnimation,
addEventListener/removeEventListener, and the onComplete handler.
---
Nitpick comments:
In `@scripts/px-to-scale-px-in-component-scss.cjs`:
- Around line 31-54: The function name findInnermostCalcRange is misleading
because it actually finds the leftmost leaf calc (a calc(...) whose body does
not contain another calc), so rename the function to findLeftmostLeafCalcRange
and update its comment accordingly; update every reference/usage of
findInnermostCalcRange in this module to the new name (e.g., callers that expect
the "innermost" behavior), and run/adjust any tests or examples that mention
findInnermostCalcRange to reflect the new identifier.
In `@src/packages/searchbar/demos/h5/demo6.tsx`:
- Around line 18-20: 在 onClick 的处理器中,当前用三元表达式切换状态 (lightTheme ?
setLightTheme(false) : setLightTheme(true)),请改为直接取反布尔值并传入 setLightTheme,例如在
onClick 回调中调用 setLightTheme(!lightTheme);定位到包含 lightTheme 和 setLightTheme 的
onClick 匿名函数并替换为布尔取反形式以简化逻辑。
In `@src/packages/timeselect/timeselect.scss`:
- Line 16: 在 src/packages/timeselect/timeselect.scss 中处理被注释的样式行 `width:
$timeselect-date-width;`:如果该样式确实不再需要,直接删除这行;如果是临时注释用于对比/测试,则恢复该行并添加简短注释说明原因和何时可删除(或在
PR 合并前再确认);确保变量 `$timeselect-date-width` 在恢复时可用且样式不会引入布局回归。
In `@src/packages/tour/tour.scss`:
- Around line 32-33: Replace the fixed 10px sizing for the close icon in
src/packages/tour/tour.scss by using the scaling helper so it respects the
adaptive system: change the width and height properties currently set to 10px to
use scale-icon-px(10px) (i.e., width: scale-icon-px(10px); height:
scale-icon-px(10px);) so the close icon sizing is consistent with the app's
scaling system.
In `@src/sites/mobile/main.tsx`:
- Line 32: 当前直接调用 initScaleF('elderly') 会在开发态 HMR 多次执行时重复注册副作用;修改为保存 initScaleF
的返回值(比如 const disposeScale = initScaleF('elderly') 或类似变量),并在 HMR 卸载阶段调用该
disposer(在 import.meta.hot?.dispose(() => disposeScale?.()) 内清理)以避免监听/副作用叠加;确保在非
HMR 环境也能安全忽略或调用该 disposer。
In `@src/utils/scale-f.ts`:
- Around line 226-242: The scale validation in calcByProfile repeats
Number(options.scale) three times; convert options.scale to a local numeric
variable once (e.g., let s = options.scale as number | undefined; or const
providedScale = options.scale) then coerce/validate that single value (Number or
Number.isFinite and > 0) and use it as currentScale, falling back to the
module-level scale; update calcByProfile to reference this single-local variable
instead of calling Number(options.scale) multiple times.
- Around line 178-188: The condition in refreshScaleF contains a redundant
defensive check "!scale" because scale is initialized to 1 and setScaleF already
ensures stored values are > 0; remove the "!scale" part and simplify the if to
only compare nextScale !== scale so the body calls setScaleF(nextScale) only
when the fetched value differs; keep the existing profile-switching logic
(setScaleProfile(nextProfile)) and the function return behavior unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 88d64b75-b933-4292-a7e0-05dcc2fd8fbc
📒 Files selected for processing (74)
.cursor/skills/nutui-proportional-scaling/SKILL.mdNutUI-React_组件标准白皮书.mdpackages/nutui-taro-demo/src/app.tsscripts/build-taro.mjsscripts/build.mjsscripts/generate-css-for-rtl-comparison.jsscripts/px-to-scale-px-in-component-scss.cjsscripts/replace-css-var.jssrc/packages/address/address.scsssrc/packages/audio/audio.scsssrc/packages/avatarcropper/avatarcropper.taro.tsxsrc/packages/button/button.taro.tsxsrc/packages/calendar/calendar.scsssrc/packages/calendarcard/calendarcard.scsssrc/packages/card/card.scsssrc/packages/checkbox/checkbox.scsssrc/packages/fixednav/fixednav.scsssrc/packages/hoverbuttonitem/hoverbuttonitem.scsssrc/packages/input/input.scsssrc/packages/inputnumber/inputnumber.scsssrc/packages/lottie/lottiemp.taro.tsxsrc/packages/menu/menu.scsssrc/packages/menu/menu.taro.tsxsrc/packages/menu/menu.tsxsrc/packages/menuitem/menuitem.scsssrc/packages/navbar/navbar.scsssrc/packages/numberkeyboard/numberkeyboard.scsssrc/packages/numberkeyboard/numberkeyboard.taro.tsxsrc/packages/numberkeyboard/numberkeyboard.tsxsrc/packages/overlay/overlay.tsxsrc/packages/popover/popover.scsssrc/packages/popover/popover.tsxsrc/packages/popup/popup.scsssrc/packages/price/price.scsssrc/packages/pulltorefresh/pulltorefresh.scsssrc/packages/quickenter/quickenter.scsssrc/packages/range/range.scsssrc/packages/rate/rate.scsssrc/packages/rate/rate.taro.tsxsrc/packages/searchbar/demos/h5/demo6.tsxsrc/packages/searchbar/searchbar.scsssrc/packages/segmented/segmented.scsssrc/packages/shortpassword/shortpassword.scsssrc/packages/space/space.scsssrc/packages/step/step.scsssrc/packages/steps/steps.scsssrc/packages/swipe/demos/h5/demo1.tsxsrc/packages/swipe/demos/h5/demo3.tsxsrc/packages/swipe/demos/h5/demo4.tsxsrc/packages/swipe/demos/h5/demo5.tsxsrc/packages/swipe/demos/h5/demo6.tsxsrc/packages/swipe/demos/h5/demo7.tsxsrc/packages/swipe/demos/h5/demo8.tsxsrc/packages/swipe/demos/h5/demo9.tsxsrc/packages/swipe/swipe.scsssrc/packages/switch/switch.scsssrc/packages/tabbar/tabbar.scsssrc/packages/tabbaritem/tabbaritem.scsssrc/packages/tabs/tabs.scsssrc/packages/tag/tag.scsssrc/packages/tag/tag.taro.tsxsrc/packages/tag/tag.tsxsrc/packages/timeselect/timeselect.scsssrc/packages/tour/tour.scsssrc/packages/uploader/uploader.scsssrc/packages/virtuallist/virtuallist.scsssrc/sites/assets/styles/highlight.scsssrc/sites/mobile/main.tsxsrc/styles/theme-dark.scsssrc/styles/theme-default.scsssrc/styles/variables.scsssrc/utils/index.taro.tssrc/utils/index.tssrc/utils/scale-f.ts
💤 Files with no reviewable changes (3)
- src/packages/overlay/overlay.tsx
- src/packages/step/step.scss
- NutUI-React_组件标准白皮书.md
| width: 10px; | ||
| height: 10px; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 搜索 CSS 自定义属性的定义和使用
rg -n '\-\-nut-icon-(width|height)' --type=scss --type=css -C3
# 搜索可能依赖这些变量的组件
rg -n 'var\(\s*--nut-icon-(width|height)' -C2Repository: jdf2e/nutui-react
Length of output: 90
🏁 Script executed:
#!/bin/bash
# Search for CSS custom properties without type restriction
rg '\-\-nut-icon-(width|height)' -C 3
# Also search for the SCSS file to understand its context
echo "=== Content of inputnumber.scss around lines 26-27 ==="
head -80 src/packages/inputnumber/inputnumber.scss | tail -60
# Search for any CSS variable definitions
echo "=== Searching for CSS variable definitions ==="
rg 'var\s*\(\s*--nut-icon' -C 2Repository: jdf2e/nutui-react
Length of output: 8070
将 .nut-icon 改为硬编码尺寸值会破坏 CSS 自定义属性机制。
在 src/styles/variables.scss 中,--nut-icon-width 和 --nut-icon-height 被定义为全局 CSS 变量,支持通过 --nut-scale-icon 进行动态缩放。此改动将这些值硬编码为 10px(第26-27行)和 16px(第69-75行),使得用户无法通过 CSS 变量统一控制该组件的图标尺寸,与 radio、checkbox 等其他组件的行为不一致。应改用 CSS 变量 var(--nut-icon-width) 和 var(--nut-icon-height) 保持一致性。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/packages/inputnumber/inputnumber.scss` around lines 26 - 27, The
.nut-icon rules were changed to hardcoded sizes (10px / 16px) which breaks the
global CSS variable scaling; restore usage of the global CSS variables by
replacing the hardcoded width and height in the .nut-icon selector(s) with
var(--nut-icon-width) and var(--nut-icon-height) so the component respects
--nut-scale-icon and matches radio/checkbox behavior (update both small and
default/large .nut-icon occurrences to use the variables).
| style={{ | ||
| fontSize: '12px', | ||
| width: '50px', | ||
| display: 'flex', | ||
| alignItems: 'center', | ||
| }} |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 描述: 查找项目中关于尺寸适配、单位转换的相关实现
# 搜索可能的适配工具函数或配置
rg -n -C3 --type=ts --type=tsx '(px2|toPx|adaptSize|scaleSize|convertUnit)' -g '!node_modules' -g '!dist'
# 搜索 SCSS 转换相关配置
fd -e js -e ts -e json 'postcss|babel|webpack' --exec grep -l 'px' {} \;
# 查找其他 demo 文件的样式写法
rg -n --type=tsx 'fontSize.*style' src/packages/searchbar/demos/Repository: jdf2e/nutui-react
Length of output: 117
🏁 Script executed:
#!/bin/bash
# Fix the initial search - use correct rg syntax and glob patterns
# Search for adaptation/sizing utilities
rg -n '(px2|toPx|adaptSize|scaleSize|convertUnit|adapt)' -g '*.ts' -g '*.tsx' -g '!node_modules' -g '!dist'
# Look at the specific file
echo "=== File content ==="
cat -n src/packages/searchbar/demos/h5/demo6.tsx | head -50
# Find other demo files to compare styling approaches
echo -e "\n=== Other demo files ==="
fd . src/packages/searchbar/demos/ -type f -name '*.tsx' | head -10Repository: jdf2e/nutui-react
Length of output: 1590
🏁 Script executed:
#!/bin/bash
# Search for sizing/adaptation related code and SCSS utilities
rg -n 'fontSize|width.*px|adapt|scale' --glob='*.scss' --glob='*.css' src/packages/ | grep -i 'adapt\|scale\|font' | head -20
# Look for postcss/babel/webpack configuration that might transform px values
fd -type f \( -name 'postcss.config.*' -o -name '.babelrc*' -o -name 'webpack.config.*' \) | head -5Repository: jdf2e/nutui-react
Length of output: 1809
🏁 Script executed:
#!/bin/bash
# Search for any adaptation system or utilities in the codebase
rg -n 'export.*function|export.*const' src/ --glob='*.ts' --glob='*.tsx' | grep -i 'adapt\|size\|scale\|px' | head -15
# Check if there are any HOCs or hooks for sizing
rg -n 'useSize|useAdapt|withSize|withAdapt' -g '*.ts' -g '*.tsx' | head -10Repository: jdf2e/nutui-react
Length of output: 383
🏁 Script executed:
#!/bin/bash
# Look at the px-transform and scale-f utilities to understand how to use them
echo "=== px-transform.ts ==="
cat -n src/utils/taro/px-transform.ts
echo -e "\n=== scale-f.ts (key functions) ==="
sed -n '1,50p' src/utils/scale-f.ts
cat -n src/utils/scale-f.ts | sed -n '191,230p'
echo -e "\n=== px-check.ts ==="
cat -n src/utils/px-check.tsRepository: jdf2e/nutui-react
Length of output: 3045
🏁 Script executed:
#!/bin/bash
# Search for how inline styles are used in other demo files
echo "=== Inline styles in demo files ==="
rg -n "style=\{\{" src/packages/searchbar/demos/ -A 5 | head -40
# Check if scale-f is imported anywhere in demos
echo -e "\n=== Import of scale utilities in demos ==="
rg -n "scale-f|pxTransform|scale-font|scale-icon" src/packages/searchbar/demos/
# Check how other components handle styling in their demos
echo -e "\n=== Other component demos with inline styles ==="
rg -n "style=\{\{" src/packages/*/demos/ -A 3 | grep -E "(fontSize|width).*px" | head -10Repository: jdf2e/nutui-react
Length of output: 4205
🏁 Script executed:
#!/bin/bash
# Look at the components to see how they use these utilities
echo "=== Searchbar component implementation ==="
cat -n src/packages/searchbar/searchbar.tsx | head -100
# Check if there are any constants or configs for sizing
rg -n "export.*const.*=.*\{" src/packages/searchbar/ -A 10 | grep -i "size\|font\|width" | head -20Repository: jdf2e/nutui-react
Length of output: 2967
🏁 Script executed:
#!/bin/bash
# Check if there are examples of using CSS variables in inline styles
echo "=== CSS variables usage in styles ==="
rg -n "var(--nut-scale" src/packages/ -A 2 -B 2 | head -30
# Check the CSS variable names in style-related files
rg -n "\-\-nut-scale" src/ --type=css --type=scss | head -20
# Look for any H5 utilities that might provide scaling
rg -n "export.*function|export.*const" src/utils/ --type=ts | grep -i "scale\|px" | head -15Repository: jdf2e/nutui-react
Length of output: 538
🏁 Script executed:
#!/bin/bash
# Check CSS variables usage in inline styles - simpler search
echo "=== CSS variable usage examples ==="
rg -n "var\(--nut" src/packages/ -A 2 -B 2 | head -40
# Check scale-f.ts to see what CSS variable names are set
echo -e "\n=== CSS variables in scale-f.ts ==="
rg -n "setProperty\|--nut-scale" src/utils/scale-f.ts -A 2 -B 2
# Check if demos use any CSS class-based styling
echo -e "\n=== CSS classes in searchbar demos ==="
rg -n "className\|style" src/packages/searchbar/demos/h5/ -B 1 -A 1 | head -50Repository: jdf2e/nutui-react
Length of output: 2516
🏁 Script executed:
#!/bin/bash
# Look at scale-f.ts more completely to understand how CSS variables are set
echo "=== Full scale-f.ts file (check for setProperty calls) ==="
cat -n src/utils/scale-f.ts | grep -E "setProperty|style\." -A 2 -B 2
# Check what the actual CSS variable names are
rg -n "nut-scale-f\|nut-scale-font\|nut-scale-icon" src/utils/ -A 1 -B 1Repository: jdf2e/nutui-react
Length of output: 554
🏁 Script executed:
#!/bin/bash
# Check if there are any other examples in the codebase of using calcByProfile or scale-f in components
echo "=== Usage of calcByProfile in components ==="
rg -n "calcByProfile\|initScaleF" src/packages/ -A 3 -B 3 | head -40
# Check if demo files import or use scale utilities
echo -e "\n=== Scale utilities imports in demos ==="
rg -n "import.*scale\|import.*calcByProfile" src/packages/*/demos/
# Check how the CSS variables should be used in inline styles
echo -e "\n=== Check if inline styles can use CSS calc with scale variables ==="
rg -n "calc\(" src/packages/ --type=tsx -B 1 -A 1 | head -20Repository: jdf2e/nutui-react
Length of output: 264
🏁 Script executed:
#!/bin/bash
# Look at the scale-f.ts file more completely to understand how it works with H5
echo "=== Check full scale-f.ts context ==="
head -100 src/utils/scale-f.ts
# Check if there's documentation on how to use the scaling system
echo -e "\n=== Check package.json or README ==="
head -50 README.md 2>/dev/null || echo "No README found"
# Look at how Taro demos handle scaling vs H5 demos
echo -e "\n=== Compare demo7 across platforms ==="
echo "=== H5 demo7 ==="
cat -n src/packages/searchbar/demos/h5/demo7.tsx | head -20
echo -e "\n=== Taro demo7 ==="
cat -n src/packages/searchbar/demos/taro/demo7.tsx | head -20Repository: jdf2e/nutui-react
Length of output: 6400
将 demo 中的硬编码像素值改为支持多尺寸适配
此 demo 中的 fontSize: '12px' 和 width: '50px' 硬编码值会绕过项目的 CSS 变量自适应系统(--nut-scale-font 等),无法在老年版/大字版等模式下正确缩放。
建议移除这些固定尺寸限制,或改用 calc() 结合 CSS 变量实现适配(如 calc(12px * var(--nut-scale-font)))。同样问题也存在于 src/packages/searchbar/demos/taro/demo6.tsx。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/packages/searchbar/demos/h5/demo6.tsx` around lines 24 - 29, The inline
styles in the demo (the style object with fontSize and width in
src/packages/searchbar/demos/h5/demo6.tsx) use hard-coded '12px' and '50px'
which bypass the project's scaling CSS variables; update the style to remove
fixed px values or replace them with calc() using the scale variable (e.g.,
calc(12px * var(--nut-scale-font))) or reference the appropriate CSS variables
so fontSize and width respect --nut-scale-font and other sizing tokens; apply
the same change to the corresponding style block in
src/packages/searchbar/demos/taro/demo6.tsx.
|
|
||
| &-right { | ||
| display: flex; | ||
| //left: 100%; |
There was a problem hiding this comment.
修复注释前缺少空行的 lint 违规
Line 35 的 //left: 100%; 前需要空行,否则会触发 scss/double-slash-comment-empty-line-before,可能导致 lint 失败。
建议修改
&-right {
display: flex;
+
//left: 100%;
height: 100%;
right: 0px;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| //left: 100%; | |
| &-right { | |
| display: flex; | |
| //left: 100%; | |
| height: 100%; | |
| right: 0px; |
🧰 Tools
🪛 Stylelint (17.11.0)
[error] 35-35: Expected empty line before comment (scss/double-slash-comment-empty-line-before)
(scss/double-slash-comment-empty-line-before)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/packages/swipe/swipe.scss` at line 35, 在包含注释文本 `//left: 100%;`
的位置前插入一个空行以修复 scss/double-slash-comment-empty-line-before lint 违规;也就是在
swipe.scss 中找到该注释并在其上一行添加一个空行,提交后 lint 应通过。
| // ---- icon size ---- | ||
| --nut-icon-height: calc( | ||
| 16px * var(--nut-scale-icon, var(--nut-scale-f, 1)) | ||
| ) !important; | ||
| --nut-icon-width: calc( | ||
| 16px * var(--nut-scale-icon, var(--nut-scale-f, 1)) | ||
| ) !important; | ||
| --nut-icon-line-height: calc( | ||
| 16px * var(--nut-scale-icon, var(--nut-scale-f, 1)) | ||
| ) !important; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 验证 --nut-icon-* (without "ui") 与 --nutui-icon-* 在仓库内的实际消费者
echo "=== consumers of --nut-icon-height/width/line-height (no 'ui') ==="
rg -nP '\bvar\(\s*--nut-icon-(height|width|line-height)\b' -g '!**/dist/**'
echo
echo "=== consumers of --nutui-icon-height/width/line-height (with 'ui') ==="
rg -nP '\bvar\(\s*--nutui-icon-(height|width|line-height)\b' -g '!**/dist/**'Repository: jdf2e/nutui-react
Length of output: 1351
:root 中 --nut-icon-* 变量的定义是死代码,需要清理。
这段定义的 --nut-icon-height、--nut-icon-width、--nut-icon-line-height 在整个仓库内无任何消费者(检索结果为空)。而真正被使用的是下方第 555-557 行定义的 --nutui-icon-*(--nutui- 前缀)及其他主题变量文件中的对应定义。
两套变量完全分离:
- Lines 8-16 定义的
--nut-icon-*及其!important从未被任何代码引用 - Lines 555-557 等定义的
--nutui-icon-*才是实际的 token 消费链
处理方案:
- 删除 Lines 8-16——这三个变量是冗余的,保留只会增加维护负担。
- 或改名为
--nutui-icon-*以统一命名空间,但需检查这样做是否会影响现有的 fallback 逻辑(Lines 555-557 的 fallback 是scale-icon-px(20px),不会被 CSS 变量覆盖)。
建议直接删除 Lines 8-16,保持命名空间统一,由 SCSS 的 scale-icon-px() 函数负责生成可缩放的图标尺寸。
🧰 Tools
🪛 Stylelint (17.11.0)
[error] 7-7: Expected empty line before comment (scss/double-slash-comment-empty-line-before)
(scss/double-slash-comment-empty-line-before)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/styles/variables.scss` around lines 7 - 17, 移除未被使用的 CSS 变量
--nut-icon-height、--nut-icon-width、--nut-icon-line-height(当前在 :root 中带
!important 的三条定义),因为仓库实际使用的是 --nutui-icon-*
系列;在文件中删除这三条冗余变量定义以统一命名空间并避免维护负担;如果确实想保留兼容性可改名为 --nutui-icon-* 并验证与现有
scale-icon-px() 的回退逻辑(位于原文件的第 555–557 行)不会被破坏。
|
|
||
| //swiper(✅) | ||
| $swiper-indicator-bottom: var(--nutui-swiper-indicator-bottom, 12px); | ||
| $swiper-indicator-bottom: var(--nutui-swiper-indicator-bottom, scale-px(12px)); |
There was a problem hiding this comment.
$swiper-indicator-bottom 缺少 !default。
本文件中其余 token 几乎都带 !default,允许在引入前由使用方覆盖。此处的赋值会无条件覆盖外部预设值,破坏 token 链路。建议补齐:
建议补充 !default
-$swiper-indicator-bottom: var(--nutui-swiper-indicator-bottom, scale-px(12px));
+$swiper-indicator-bottom: var(
+ --nutui-swiper-indicator-bottom,
+ scale-px(12px)
+) !default;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| $swiper-indicator-bottom: var(--nutui-swiper-indicator-bottom, scale-px(12px)); | |
| $swiper-indicator-bottom: var( | |
| --nutui-swiper-indicator-bottom, | |
| scale-px(12px) | |
| ) !default; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/styles/variables.scss` at line 1353, The SCSS token
$swiper-indicator-bottom is being assigned unconditionally which overrides
external presets; update the declaration of $swiper-indicator-bottom to append
!default (i.e., change the assignment so it becomes a defaultable variable) so
it can be overridden by consumers and remain consistent with other tokens in the
file.
| /** 首次计算缩放并订阅 resize;返回卸载函数(SSR 下为空函数) */ | ||
| export function initScaleF(nextProfile?: ScaleProfile) { | ||
| if (!canUseDom) return () => {} | ||
| setScaleProfile(nextProfile) | ||
|
|
||
| const handler = () => { | ||
| refreshScaleF() | ||
| } | ||
|
|
||
| handler() | ||
| window.addEventListener('resize', handler) | ||
|
|
||
| return () => { | ||
| window.removeEventListener('resize', handler) | ||
| } | ||
| } |
There was a problem hiding this comment.
resize 处理存在竞态与重复注册风险。
当前实现有两个问题:
- 没有节流/防抖:浏览器或软键盘弹起时
resize会在很短时间内高频触发,每次都会触发一个refreshScaleF()(其内部await getScaleByNative()通过原生桥),多个异步请求并发返回时,完成顺序无法保证——较早发起的请求可能在较晚发起的之后才 resolve,最终把"旧 scale" 覆盖回:root,导致页面尺寸闪烁或回到错误值。 initScaleF没有幂等保护:被重复调用(HMR、Taro 页面多次 mount、demo 切换路由再回来等)时会反复addEventListener('resize', handler),监听器会堆积,dispose 函数只能解掉最后一次返回的 handler。
建议:
- 用
requestAnimationFrame合并多次 resize 或加一个简单防抖; - 用一个递增 token 标记每次刷新,回写 CSS 变量前比对 token,过期请求直接丢弃;
- 在
initScaleF中维护一个 module-level disposer,重复调用时先调用旧 disposer 再重新订阅。
参考实现
-let scale = 1
+let scale = 1
+let activeDisposer: (() => void) | null = null
+let refreshToken = 0
@@
-/** 重新拉取缩放;可选同时切换 profile,避免与当前值相同时重复写 DOM */
-async function refreshScaleF(nextProfile?: ScaleProfile) {
- if (nextProfile) {
- setScaleProfile(nextProfile)
- }
- const nextScale = await getScaleF()
- if (!scale || nextScale !== scale) {
- setScaleF(nextScale)
- }
- return scale
-}
+async function refreshScaleF(nextProfile?: ScaleProfile) {
+ if (nextProfile) {
+ setScaleProfile(nextProfile)
+ }
+ const token = ++refreshToken
+ const nextScale = await getScaleF()
+ if (token !== refreshToken) return scale // 过期请求丢弃
+ if (nextScale !== scale) setScaleF(nextScale)
+ return scale
+}
@@
export function initScaleF(nextProfile?: ScaleProfile) {
if (!canUseDom) return () => {}
+ if (activeDisposer) activeDisposer()
setScaleProfile(nextProfile)
- const handler = () => {
- refreshScaleF()
- }
+ let rafId = 0
+ const handler = () => {
+ if (rafId) cancelAnimationFrame(rafId)
+ rafId = requestAnimationFrame(() => {
+ rafId = 0
+ refreshScaleF()
+ })
+ }
handler()
window.addEventListener('resize', handler)
- return () => {
- window.removeEventListener('resize', handler)
- }
+ activeDisposer = () => {
+ if (rafId) cancelAnimationFrame(rafId)
+ window.removeEventListener('resize', handler)
+ activeDisposer = null
+ }
+ return activeDisposer
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/utils/scale-f.ts` around lines 190 - 205, The resize handler in
initScaleF can cause high-frequency concurrent refreshScaleF() calls (which
await getScaleByNative()) and also allows duplicate listeners; make initScaleF
idempotent by storing a module-level disposer and calling it at start to remove
any existing listener before registering a new one, debounce/coalesce resize
events using requestAnimationFrame (or a short timer) inside the handler to
avoid rapid concurrent calls, and implement a monotonically incremented
token/version in refreshScaleF/getScaleByNative flow so each async response
compares its token before writing CSS variables (drop outdated responses);
ensure the same handler reference is used for
addEventListener/removeEventListener so the disposer reliably removes the
listener.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.cursor/skills/nutui-proportional-scaling/SKILL.md:
- Line 56: The Markdown contains an escaped bold marker (\*\*) causing literal
asterisks to render; update the sentence that mentions scripts
(scripts/replace-css-var.js, scripts/build.mjs, scripts/build-taro.mjs,
scripts/px-to-scale-px-in-component-scss.cjs) and change the fragment
"不写回\*\*仓库里的组件 SCSS" to use a proper bold marker (e.g., "不写回**仓库里的组件 SCSS**" or
remove the asterisks entirely) so the bold formatting closes correctly and no
backslashes remain.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 9ea9008b-10c9-4686-8d09-34f3e9c6fa83
📒 Files selected for processing (6)
.cursor/skills/nutui-proportional-scaling/SKILL.mdsrc/packages/avatarcropper/avatarcropper.taro.tsxsrc/packages/checkbox/checkbox.scsssrc/packages/fixednav/fixednav.scsssrc/packages/lottie/lottiemp.taro.tsxsrc/packages/popover/popover.taro.tsx
✅ Files skipped from review due to trivial changes (1)
- src/packages/avatarcropper/avatarcropper.taro.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- src/packages/checkbox/checkbox.scss
|
|
||
| ### 2.1 `npm run build` / `npm run build:taro` 时的 px → `scale-px` | ||
|
|
||
| - 与 `package.json` 中顺序一致:先跑 **`scripts/replace-css-var.js`**,再 **`scripts/build.mjs`** 或 **`scripts/build-taro.mjs`**;上述脚本在读取 **`src/packages/**/\*.scss`(不含 demo)** 后,会经 **`scripts/px-to-scale-px-in-component-scss.cjs`** 在**内存**里把声明值中的裸 **`Npx`** 转为 **`scale-px(Npx)`**(规则见 §3),**不写回\*\*仓库里的组件 SCSS。 |
There was a problem hiding this comment.
修复 Markdown 格式问题。
此行存在 Markdown 转义错误,不写回\*\*仓库里的组件 中的 \*\* 会显示为字面星号而非加粗结束标记,导致渲染异常。
📝 建议的修复
-在**内存**里把声明值中的裸 **`Npx`** 转为 **`scale-px(Npx)`**(规则见 §3),**不写回\*\*仓库里的组件 SCSS。
+在**内存**里把声明值中的裸 **`Npx`** 转为 **`scale-px(Npx)`**(规则见 §3),**不写回**仓库里的组件 SCSS。📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - 与 `package.json` 中顺序一致:先跑 **`scripts/replace-css-var.js`**,再 **`scripts/build.mjs`** 或 **`scripts/build-taro.mjs`**;上述脚本在读取 **`src/packages/**/\*.scss`(不含 demo)** 后,会经 **`scripts/px-to-scale-px-in-component-scss.cjs`** 在**内存**里把声明值中的裸 **`Npx`** 转为 **`scale-px(Npx)`**(规则见 §3),**不写回\*\*仓库里的组件 SCSS。 | |
| - 与 `package.json` 中顺序一致:先跑 **`scripts/replace-css-var.js`**,再 **`scripts/build.mjs`** 或 **`scripts/build-taro.mjs`**;上述脚本在读取 **`src/packages/**/\*.scss`(不含 demo)** 后,会经 **`scripts/px-to-scale-px-in-component-scss.cjs`** 在**内存**里把声明值中的裸 **`Npx`** 转为 **`scale-px(Npx)`**(规则见 §3),**不写回**仓库里的组件 SCSS。 |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.cursor/skills/nutui-proportional-scaling/SKILL.md at line 56, The Markdown
contains an escaped bold marker (\*\*) causing literal asterisks to render;
update the sentence that mentions scripts (scripts/replace-css-var.js,
scripts/build.mjs, scripts/build-taro.mjs,
scripts/px-to-scale-px-in-component-scss.cjs) and change the fragment
"不写回\*\*仓库里的组件 SCSS" to use a proper bold marker (e.g., "不写回**仓库里的组件 SCSS**" or
remove the asterisks entirely) so the bold formatting closes correctly and no
backslashes remain.
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
src/styles/variables.scss (1)
2857-2864: ⚡ Quick winTrendArrow token 被重复定义,建议去重。
Line 2857-2864 与 Line 2907-2914 的
$trendarrow-font-size、$trendarrow-icon-margin完全重复,后定义会静默覆盖前定义,后续维护容易漂移。建议仅保留一处。建议修改
-// TrendArrow -$trendarrow-font-size: var( - --nutui-trendarrow-font-size, - $font-size-base -) !default; -$trendarrow-icon-margin: var( - --nutui-trendarrow-icon-margin, - scale-px(4px) -) !default;Also applies to: 2907-2914
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/styles/variables.scss` around lines 2857 - 2864, The two SCSS tokens $trendarrow-font-size and $trendarrow-icon-margin are defined twice (the blocks at lines reported) causing silent overrides; remove the duplicate block so only a single canonical definition remains (keep the desired instance with the var(...) fallback and !default), verify the remaining definition uses the same values (var(--nutui-trendarrow-font-size, $font-size-base) and var(--nutui-trendarrow-icon-margin, scale-px(4px))) and ensure no other duplicates exist so maintenance won’t silently override these tokens.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/packages/card/card.scss`:
- Line 30: 在 src/packages/card/card.scss 中,声明 "line-height: $line-height-xl;"
前缺少按 stylelint
规则要求的空行(declaration-empty-line-before),请在该声明前插入一个空行以满足样式检查;确保仅对该声明添加空行而不改变其他缩进或语义。
In `@src/styles/theme-dark.scss`:
- Line 261: The SCSS file has single-line comments like "// 标准内容、名称类关键信息" that
violate the scss/double-slash-comment-empty-line-before rule; add a blank line
immediately before each offending double-slash comment (the occurrences
containing the text "标准内容、名称类关键信息" and the other comments at the same pattern on
the listed lines) so each // comment is preceded by an empty line to satisfy
stylelint.
In `@src/styles/theme-default.scss`:
- Line 260: The SCSS file contains single-line comments like "// 标准内容、名称类关键信息"
that are triggering the stylelint rule
scss/double-slash-comment-empty-line-before on several lines; fix by inserting
the required empty line(s) before each double-slash comment (e.g., the comment
text "// 标准内容、名称类关键信息") so the comment is preceded by a blank line as expected
by the linter across the affected occurrences.
In `@src/styles/variables.scss`:
- Around line 309-312: Fix the stylelint violations for
scss/dollar-variable-empty-line-before and
scss/double-slash-comment-empty-line-before by making spacing consistent around
SCSS variable declarations and single-line comments in variables.scss;
specifically adjust the blank line before the $button-xlarge-height declaration
and any other nearby $-variables or // comments so they either have the required
empty line or none (matching your project rule), and re-run stylelint to verify
and fix the remaining occurrences reported (e.g., around $button-xlarge-height
and other $variable and // comment blocks referenced in the review).
---
Nitpick comments:
In `@src/styles/variables.scss`:
- Around line 2857-2864: The two SCSS tokens $trendarrow-font-size and
$trendarrow-icon-margin are defined twice (the blocks at lines reported) causing
silent overrides; remove the duplicate block so only a single canonical
definition remains (keep the desired instance with the var(...) fallback and
!default), verify the remaining definition uses the same values
(var(--nutui-trendarrow-font-size, $font-size-base) and
var(--nutui-trendarrow-icon-margin, scale-px(4px))) and ensure no other
duplicates exist so maintenance won’t silently override these tokens.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 98e5583f-f4a3-4f83-84c8-fb52864a7c6e
📒 Files selected for processing (18)
src/packages/calendarcard/calendarcard.scsssrc/packages/card/card.scsssrc/packages/checkbox/checkbox.scsssrc/packages/hoverbuttonitem/hoverbuttonitem.scsssrc/packages/menu/menu.scsssrc/packages/navbar/navbar.scsssrc/packages/numberkeyboard/numberkeyboard.scsssrc/packages/price/price.scsssrc/packages/quickenter/quickenter.scsssrc/packages/rate/rate.scsssrc/packages/searchbar/searchbar.scsssrc/packages/steps/steps.scsssrc/packages/tabs/tabs.scsssrc/packages/tag/tag.scsssrc/packages/virtuallist/virtuallist.scsssrc/styles/theme-dark.scsssrc/styles/theme-default.scsssrc/styles/variables.scss
✅ Files skipped from review due to trivial changes (8)
- src/packages/virtuallist/virtuallist.scss
- src/packages/tabs/tabs.scss
- src/packages/menu/menu.scss
- src/packages/hoverbuttonitem/hoverbuttonitem.scss
- src/packages/tag/tag.scss
- src/packages/navbar/navbar.scss
- src/packages/quickenter/quickenter.scss
- src/packages/steps/steps.scss
🚧 Files skipped from review as they are similar to previous changes (5)
- src/packages/searchbar/searchbar.scss
- src/packages/checkbox/checkbox.scss
- src/packages/numberkeyboard/numberkeyboard.scss
- src/packages/calendarcard/calendarcard.scss
- src/packages/price/price.scss
| @include moreline-ellipsis(); | ||
| line-height: 1.5; | ||
| font-size: 14px; | ||
| line-height: $line-height-xl; |
There was a problem hiding this comment.
Line 30 存在声明前空行的 stylelint 违规。
请在该声明前按规则补空行(declaration-empty-line-before),避免样式检查失败。
🧰 Tools
🪛 Stylelint (17.11.0)
[error] 30-30: Expected empty line before declaration (declaration-empty-line-before)
(declaration-empty-line-before)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/packages/card/card.scss` at line 30, 在 src/packages/card/card.scss 中,声明
"line-height: $line-height-xl;" 前缺少按 stylelint
规则要求的空行(declaration-empty-line-before),请在该声明前插入一个空行以满足样式检查;确保仅对该声明添加空行而不改变其他缩进或语义。
| // 汉字:次要内容、辅助类信息 数字:羊角符号、小数点及角分 | ||
| --nutui-font-size-s: var(--nutui-font-size-12); | ||
| --nutui-font-size-m: var(--nutui-font-size-13); | ||
| // 标准内容、名称类关键信息 |
There was a problem hiding this comment.
请补齐注释前空行以通过 stylelint。
Line 261、263、265、268、270 触发 scss/double-slash-comment-empty-line-before,建议按规则补一个空行。
Also applies to: 263-263, 265-265, 268-268, 270-270
🧰 Tools
🪛 Stylelint (17.11.0)
[error] 261-261: Expected empty line before comment (scss/double-slash-comment-empty-line-before)
(scss/double-slash-comment-empty-line-before)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/styles/theme-dark.scss` at line 261, The SCSS file has single-line
comments like "// 标准内容、名称类关键信息" that violate the
scss/double-slash-comment-empty-line-before rule; add a blank line immediately
before each offending double-slash comment (the occurrences containing the text
"标准内容、名称类关键信息" and the other comments at the same pattern on the listed lines)
so each // comment is preceded by an empty line to satisfy stylelint.
| // 汉字:次要内容、辅助类信息 数字:羊角符号、小数点及角分 | ||
| --nutui-font-size-s: var(--nutui-font-size-12); | ||
| --nutui-font-size-m: var(--nutui-font-size-13); | ||
| // 标准内容、名称类关键信息 |
There was a problem hiding this comment.
这里有注释空行的 stylelint 错误。
Line 260、262、264、267、269 触发 scss/double-slash-comment-empty-line-before,建议补齐空行保持 CI 通过。
Also applies to: 262-262, 264-264, 267-267, 269-269
🧰 Tools
🪛 Stylelint (17.11.0)
[error] 260-260: Expected empty line before comment (scss/double-slash-comment-empty-line-before)
(scss/double-slash-comment-empty-line-before)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/styles/theme-default.scss` at line 260, The SCSS file contains
single-line comments like "// 标准内容、名称类关键信息" that are triggering the stylelint
rule scss/double-slash-comment-empty-line-before on several lines; fix by
inserting the required empty line(s) before each double-slash comment (e.g., the
comment text "// 标准内容、名称类关键信息") so the comment is preceded by a blank line as
expected by the linter across the affected occurrences.
| $button-xlarge-height: var( | ||
| --nutui-button-xlarge-height, | ||
| scale-px(48px) | ||
| ) !default; |
There was a problem hiding this comment.
请修复这些 stylelint 违规,避免样式检查阻塞。
Line 309、330、358、459、579、2231、2730 附近存在 scss/dollar-variable-empty-line-before / scss/double-slash-comment-empty-line-before 规则错误,建议统一补齐或移除空行后再提交。
Also applies to: 330-330, 358-361, 459-462, 579-579, 2231-2231, 2730-2731
🧰 Tools
🪛 Stylelint (17.11.0)
[error] 309-312: Unexpected empty line before $-variable (scss/dollar-variable-empty-line-before)
(scss/dollar-variable-empty-line-before)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/styles/variables.scss` around lines 309 - 312, Fix the stylelint
violations for scss/dollar-variable-empty-line-before and
scss/double-slash-comment-empty-line-before by making spacing consistent around
SCSS variable declarations and single-line comments in variables.scss;
specifically adjust the blank line before the $button-xlarge-height declaration
and any other nearby $-variables or // comments so they either have the required
empty line or none (matching your project rule), and re-run stylelint to verify
and fix the remaining occurrences reported (e.g., around $button-xlarge-height
and other $variable and // comment blocks referenced in the review).
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/packages/calendarcard/calendarcard.scss (1)
70-77:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
$font-size-s与固定12px行盒组合有裁切风险。
Line 76改为字体 token 后,Line 75和Line 77仍固定为12px。在大字/老年倍率下,文本可能被压缩或截断。建议让行高(必要时高度)与字体缩放保持一致。🛠 建议修改
&-top, &-bottom { display: flex; align-items: center; justify-content: center; width: 100%; - height: 12px; + height: scale-font-px(12px); font-size: $font-size-s; - line-height: 12px; + line-height: scale-font-px(12px); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/packages/calendarcard/calendarcard.scss` around lines 70 - 77, The .calendarcard &-bottom rule uses $font-size-s with a fixed 12px line-height and height, which can cause clipping at larger font scales; update the &-bottom declaration so line-height and height are tied to the font token (or use a scalable unit) — e.g. replace line-height: 12px and height: 12px with a line-height that matches the font-size token (or a relative value like 1) and set height to auto or min-height using the same token (reference: the &-bottom selector and $font-size-s variable).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/packages/calendarcard/calendarcard.scss`:
- Around line 70-77: The .calendarcard &-bottom rule uses $font-size-s with a
fixed 12px line-height and height, which can cause clipping at larger font
scales; update the &-bottom declaration so line-height and height are tied to
the font token (or use a scalable unit) — e.g. replace line-height: 12px and
height: 12px with a line-height that matches the font-size token (or a relative
value like 1) and set height to auto or min-height using the same token
(reference: the &-bottom selector and $font-size-s variable).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: e8f29c29-9af5-4979-8262-819c55efa713
📒 Files selected for processing (21)
.cursor/skills/nutui-proportional-scaling/SKILL.mdsrc/packages/calendarcard/calendarcard.scsssrc/packages/card/card.scsssrc/packages/inputnumber/inputnumber.taro.tsxsrc/packages/menuitem/menuitem.taro.tsxsrc/packages/noticebar/noticebar.scsssrc/packages/noticebar/noticebar.taro.tsxsrc/packages/noticebar/noticebar.tsxsrc/packages/notify/notify.scsssrc/packages/notify/notify.taro.tsxsrc/packages/numberkeyboard/numberkeyboard.scsssrc/packages/numberkeyboard/numberkeyboard.tsxsrc/packages/rate/rate.scsssrc/packages/segmented/segmented.scsssrc/packages/shortpassword/shortpassword.scsssrc/packages/shortpassword/shortpassword.taro.tsxsrc/packages/shortpassword/shortpassword.tsxsrc/packages/tabs/tabs.scsssrc/packages/tabs/tabs.taro.tsxsrc/packages/tabs/tabs.tsxsrc/styles/variables.scss
💤 Files with no reviewable changes (2)
- src/packages/menuitem/menuitem.taro.tsx
- src/packages/inputnumber/inputnumber.taro.tsx
✅ Files skipped from review due to trivial changes (4)
- src/packages/tabs/tabs.tsx
- src/packages/numberkeyboard/numberkeyboard.scss
- src/packages/segmented/segmented.scss
- src/packages/rate/rate.scss
🚧 Files skipped from review as they are similar to previous changes (1)
- src/packages/tabs/tabs.scss
🤔 这个变动的性质是?
🔗 相关 Issue
💡 需求背景和解决方案
☑️ 请求合并前的自查清单
Summary by CodeRabbit
New Features
Improvements
Documentation