zkit-ui 1.0.0 → 1.0.2
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/dist/ui/Button/index.d.ts.map +1 -1
- package/dist/ui/Button/index.js +164 -15
- package/dist/ui/Checkbox/index.d.ts.map +1 -1
- package/dist/ui/Checkbox/index.js +18 -4
- package/dist/ui/Radio/index.d.ts.map +1 -1
- package/dist/ui/Radio/index.js +17 -6
- package/dist/ui/Text/index.d.ts.map +1 -1
- package/dist/ui/Text/index.js +65 -17
- package/package.json +1 -1
- package/src/ui/Button/README.md +5 -1
- package/src/ui/Button/index.tsx +388 -54
- package/src/ui/Checkbox/README.md +4 -1
- package/src/ui/Checkbox/index.tsx +19 -4
- package/src/ui/Radio/README.md +4 -1
- package/src/ui/Radio/index.tsx +23 -10
- package/src/ui/Text/README.md +5 -2
- package/src/ui/Text/index.tsx +107 -32
package/src/ui/Text/README.md
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
- 默认使用 `getMaxFontSizeMultiplier()` 限制字体缩放上限,单次可用 `maxFontSizeMultiplier` 覆盖。
|
|
11
11
|
- Android 默认关闭 `includeFontPadding`,用明确 lineHeight 保证 iOS / Android / Web 视觉高度更一致。
|
|
12
12
|
- `color` 支持主题 token、语义色 token 和原生可解析颜色;无效颜色会回落到 `tone`。
|
|
13
|
+
- `style.fontSize` 作为最终 escape hatch 覆盖字号时,如果没有显式 `lineHeight`,组件不会继续注入默认行高,会交给原生 Text 按字体度量排版。
|
|
14
|
+
- 嵌套在 zkit `Text` 内部的 `Text`,未显式传入 `variant / size / lineHeight / style.fontSize / style.lineHeight` 时会继承父级排版。
|
|
13
15
|
- 屏幕宽度变化时会重新计算排版尺寸,横竖屏和分屏场景不会卡在初始化尺寸。
|
|
14
16
|
|
|
15
17
|
## 基础用法
|
|
@@ -22,7 +24,7 @@ export function Demo() {
|
|
|
22
24
|
}
|
|
23
25
|
```
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
单独使用时默认等价于:
|
|
26
28
|
|
|
27
29
|
- `variant="body"`
|
|
28
30
|
- `tone="default"`
|
|
@@ -52,7 +54,7 @@ export function Demo() {
|
|
|
52
54
|
}
|
|
53
55
|
```
|
|
54
56
|
|
|
55
|
-
`variant` 只决定默认 `size / weight / fontFamily`,显式传入 `size`、`weight` 或 `style`
|
|
57
|
+
`variant` 只决定默认 `size / weight / fontFamily`,显式传入 `size`、`weight` 或 `style` 时会覆盖对应值。嵌套 `Text` 未显式声明排版时不会重新套用默认 `body`,以保持内联链接、强调文案和协议文字的字号稳定。
|
|
56
58
|
|
|
57
59
|
## 尺寸
|
|
58
60
|
|
|
@@ -88,6 +90,7 @@ export function Demo() {
|
|
|
88
90
|
| `4xl` | `wp(36)` | `wp(44)` |
|
|
89
91
|
|
|
90
92
|
传入数字 `size` 或 `lineHeight` 时,数字代表未缩放的设计像素,组件内部会统一转换。
|
|
93
|
+
通过 `style.fontSize` 直接覆盖字号时,调用侧应传入已经计算好的原生字号;如果没有同时传入 `lineHeight` 或 `style.lineHeight`,组件会移除内置 token 行高,避免字号和行高不匹配。
|
|
91
94
|
|
|
92
95
|
## 颜色
|
|
93
96
|
|
package/src/ui/Text/index.tsx
CHANGED
|
@@ -173,6 +173,9 @@ const baseStyles = StyleSheet.create({
|
|
|
173
173
|
},
|
|
174
174
|
});
|
|
175
175
|
|
|
176
|
+
const DEFAULT_LINE_HEIGHT_RATIO = 1.4;
|
|
177
|
+
const NestedTextContext = React.createContext(false);
|
|
178
|
+
|
|
176
179
|
function isFiniteNumber(value: unknown): value is number {
|
|
177
180
|
return typeof value === 'number' && Number.isFinite(value);
|
|
178
181
|
}
|
|
@@ -306,23 +309,62 @@ function resolveTypographyToken(size: TextSizeValue): TypographyToken {
|
|
|
306
309
|
const fontSize = Math.max(0, size);
|
|
307
310
|
return {
|
|
308
311
|
fontSize,
|
|
309
|
-
lineHeight: Math.ceil(fontSize *
|
|
312
|
+
lineHeight: Math.ceil(fontSize * DEFAULT_LINE_HEIGHT_RATIO),
|
|
310
313
|
};
|
|
311
314
|
}
|
|
312
315
|
|
|
313
|
-
function
|
|
314
|
-
const
|
|
315
|
-
return
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
316
|
+
function readStyleNumber(style: TextStyle | undefined, key: 'fontSize' | 'lineHeight') {
|
|
317
|
+
const value = style?.[key];
|
|
318
|
+
return isFiniteNumber(value) ? Math.max(0, value) : undefined;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function resolveTypographyStyle({
|
|
322
|
+
explicitLineHeight,
|
|
323
|
+
hasExplicitSize,
|
|
324
|
+
shouldUseVariantDefaults,
|
|
325
|
+
size,
|
|
326
|
+
styleFontSize,
|
|
327
|
+
styleLineHeight,
|
|
328
|
+
}: {
|
|
329
|
+
explicitLineHeight: number | undefined;
|
|
330
|
+
hasExplicitSize: boolean;
|
|
331
|
+
shouldUseVariantDefaults: boolean;
|
|
332
|
+
size: TextSizeValue;
|
|
333
|
+
styleFontSize: number | undefined;
|
|
334
|
+
styleLineHeight: number | undefined;
|
|
335
|
+
}): TextStyle | undefined {
|
|
336
|
+
const shouldResolveSize = hasExplicitSize || shouldUseVariantDefaults;
|
|
337
|
+
const token = shouldResolveSize ? resolveTypographyToken(size) : undefined;
|
|
338
|
+
const nextStyle: TextStyle = {};
|
|
339
|
+
let hasStyle = false;
|
|
340
|
+
|
|
341
|
+
if (token) {
|
|
342
|
+
nextStyle.fontSize = wp(token.fontSize);
|
|
343
|
+
hasStyle = true;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (styleLineHeight != null) {
|
|
347
|
+
return hasStyle ? nextStyle : undefined;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (isFiniteNumber(explicitLineHeight)) {
|
|
351
|
+
nextStyle.lineHeight = wp(Math.max(0, explicitLineHeight));
|
|
352
|
+
hasStyle = true;
|
|
353
|
+
} else if (token && styleFontSize == null) {
|
|
354
|
+
nextStyle.lineHeight = wp(token.lineHeight);
|
|
355
|
+
hasStyle = true;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return hasStyle ? nextStyle : undefined;
|
|
319
359
|
}
|
|
320
360
|
|
|
321
|
-
function normalizeStyleFontWeight(
|
|
361
|
+
function normalizeStyleFontWeight(
|
|
362
|
+
style: StyleProp<TextStyle>,
|
|
363
|
+
flattenedStyle: TextStyle | undefined
|
|
364
|
+
): StyleProp<TextStyle> {
|
|
322
365
|
if (!style) return style;
|
|
323
366
|
|
|
324
|
-
const
|
|
325
|
-
const fontWeight = flattened?.fontWeight;
|
|
367
|
+
const fontWeight = flattenedStyle?.fontWeight;
|
|
326
368
|
if (fontWeight == null) return style;
|
|
327
369
|
|
|
328
370
|
const normalizedFontWeight = normalizeFontWeight(fontWeight);
|
|
@@ -352,7 +394,7 @@ function resolveAccessibilityState(
|
|
|
352
394
|
|
|
353
395
|
const TextBase = React.forwardRef<TextRef, TextProps>(function Text(
|
|
354
396
|
{
|
|
355
|
-
variant
|
|
397
|
+
variant: variantProp,
|
|
356
398
|
size,
|
|
357
399
|
lineHeight,
|
|
358
400
|
weight,
|
|
@@ -374,11 +416,16 @@ const TextBase = React.forwardRef<TextRef, TextProps>(function Text(
|
|
|
374
416
|
},
|
|
375
417
|
ref
|
|
376
418
|
) {
|
|
419
|
+
const nested = React.useContext(NestedTextContext);
|
|
377
420
|
const theme = useTheme();
|
|
378
421
|
const { width: viewportWidth } = useWindowDimensions();
|
|
422
|
+
const hasExplicitVariant = variantProp != null;
|
|
423
|
+
const shouldUseVariantDefaults = !nested || hasExplicitVariant;
|
|
424
|
+
const variant = variantProp ?? 'body';
|
|
379
425
|
const variantToken: VariantToken = VARIANT_TOKENS[variant] ?? VARIANT_TOKENS.body;
|
|
426
|
+
const hasExplicitSize = size != null;
|
|
380
427
|
const resolvedSize = size ?? variantToken.size;
|
|
381
|
-
const resolvedWeight = weight ?? variantToken.weight;
|
|
428
|
+
const resolvedWeight = weight ?? (shouldUseVariantDefaults ? variantToken.weight : undefined);
|
|
382
429
|
const toneColor = resolveToneColor(theme.colors, disabled ? 'disabled' : tone);
|
|
383
430
|
const resolvedColor = resolveColorToken(color, toneColor, theme);
|
|
384
431
|
const resolvedNumberOfLines = resolveNumberOfLines(truncate, numberOfLines);
|
|
@@ -388,20 +435,45 @@ const TextBase = React.forwardRef<TextRef, TextProps>(function Text(
|
|
|
388
435
|
[accessibilityState, disabled]
|
|
389
436
|
);
|
|
390
437
|
|
|
438
|
+
const flattenedStyle = React.useMemo(() => StyleSheet.flatten(style), [style]);
|
|
439
|
+
const styleFontSize = readStyleNumber(flattenedStyle, 'fontSize');
|
|
440
|
+
const styleLineHeight = readStyleNumber(flattenedStyle, 'lineHeight');
|
|
391
441
|
const typographyStyle = React.useMemo(
|
|
392
|
-
() =>
|
|
393
|
-
|
|
442
|
+
() =>
|
|
443
|
+
resolveTypographyStyle({
|
|
444
|
+
explicitLineHeight: lineHeight,
|
|
445
|
+
hasExplicitSize,
|
|
446
|
+
shouldUseVariantDefaults,
|
|
447
|
+
size: resolvedSize,
|
|
448
|
+
styleFontSize,
|
|
449
|
+
styleLineHeight,
|
|
450
|
+
}),
|
|
451
|
+
[
|
|
452
|
+
hasExplicitSize,
|
|
453
|
+
lineHeight,
|
|
454
|
+
resolvedSize,
|
|
455
|
+
shouldUseVariantDefaults,
|
|
456
|
+
styleFontSize,
|
|
457
|
+
styleLineHeight,
|
|
458
|
+
viewportWidth,
|
|
459
|
+
]
|
|
394
460
|
);
|
|
395
461
|
|
|
396
462
|
const semanticStyle = React.useMemo<TextStyle>(() => {
|
|
397
463
|
const nextStyle: TextStyle = {
|
|
398
|
-
fontFamily: variantToken.fontFamily,
|
|
399
464
|
fontVariant: tabularNumbers ? ['tabular-nums'] : undefined,
|
|
400
|
-
fontWeight: normalizeFontWeight(resolveTextWeight(resolvedWeight)),
|
|
401
465
|
textAlign: align,
|
|
402
466
|
textTransform: transform,
|
|
403
467
|
};
|
|
404
468
|
|
|
469
|
+
if (shouldUseVariantDefaults && variantToken.fontFamily !== undefined) {
|
|
470
|
+
nextStyle.fontFamily = variantToken.fontFamily;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (resolvedWeight !== undefined) {
|
|
474
|
+
nextStyle.fontWeight = normalizeFontWeight(resolveTextWeight(resolvedWeight));
|
|
475
|
+
}
|
|
476
|
+
|
|
405
477
|
if (resolvedColor !== undefined) {
|
|
406
478
|
nextStyle.color = resolvedColor;
|
|
407
479
|
}
|
|
@@ -411,12 +483,13 @@ const TextBase = React.forwardRef<TextRef, TextProps>(function Text(
|
|
|
411
483
|
align,
|
|
412
484
|
resolvedColor,
|
|
413
485
|
resolvedWeight,
|
|
486
|
+
shouldUseVariantDefaults,
|
|
414
487
|
tabularNumbers,
|
|
415
488
|
transform,
|
|
416
489
|
variantToken.fontFamily,
|
|
417
490
|
]);
|
|
418
491
|
|
|
419
|
-
const normalizedStyle = React.useMemo(() => normalizeStyleFontWeight(style), [style]);
|
|
492
|
+
const normalizedStyle = React.useMemo(() => normalizeStyleFontWeight(style, flattenedStyle), [flattenedStyle, style]);
|
|
420
493
|
const finalStyle = React.useMemo<StyleProp<TextStyle>>(
|
|
421
494
|
() =>
|
|
422
495
|
normalizedStyle
|
|
@@ -426,21 +499,23 @@ const TextBase = React.forwardRef<TextRef, TextProps>(function Text(
|
|
|
426
499
|
);
|
|
427
500
|
|
|
428
501
|
return (
|
|
429
|
-
<
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
502
|
+
<NestedTextContext.Provider value>
|
|
503
|
+
<RNText
|
|
504
|
+
ref={ref}
|
|
505
|
+
{...rest}
|
|
506
|
+
accessibilityState={resolvedAccessibilityState}
|
|
507
|
+
allowFontScaling={allowFontScaling}
|
|
508
|
+
disabled={disabled}
|
|
509
|
+
ellipsizeMode={resolvedEllipsizeMode}
|
|
510
|
+
maxFontSizeMultiplier={
|
|
511
|
+
allowFontScaling === false ? maxFontSizeMultiplier : (maxFontSizeMultiplier ?? getMaxFontSizeMultiplier())
|
|
512
|
+
}
|
|
513
|
+
numberOfLines={resolvedNumberOfLines}
|
|
514
|
+
style={finalStyle}
|
|
515
|
+
>
|
|
516
|
+
{children}
|
|
517
|
+
</RNText>
|
|
518
|
+
</NestedTextContext.Provider>
|
|
444
519
|
);
|
|
445
520
|
});
|
|
446
521
|
|