mobile-design 0.1.1 → 0.1.3

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.
@@ -539,7 +539,8 @@ function MenuItem({
539
539
  const { fontScale } = useWindowDimensions();
540
540
  const colors = roleColors(theme, variant);
541
541
  const disabled = Boolean(item.disabled || (item.items && !item.items.length));
542
- const [width, setWidth] = useState(56);
542
+ const iconSpace = item.icon ? 32 : 0;
543
+ const [labelWidth, setLabelWidth] = useState<number | null>(null);
543
544
  const [height, setHeight] = useState(56);
544
545
  const [focused, setFocused] = useState(false);
545
546
  const [hovered, setHovered] = useState(false);
@@ -568,7 +569,9 @@ function MenuItem({
568
569
  },
569
570
  [alpha, widthFraction]
570
571
  );
571
- const naturalWidth = Math.max(56, Math.min(maxWidth, width));
572
+ // Keep the icon space live even before native text layout reports a new measurement.
573
+ const measuredWidth = labelWidth === null ? 56 : labelWidth + 49 + iconSpace;
574
+ const naturalWidth = Math.max(56, Math.min(maxWidth, measuredWidth));
572
575
  const geometry = useAnimatedStyle(() => ({ width: naturalWidth * Math.max(0, widthFraction.get()) }));
573
576
  const fade = useAnimatedStyle(() => ({ opacity: Math.max(0, Math.min(1, alpha.get())) }));
574
577
  const contentOffset = useAnimatedStyle(() => {
@@ -661,19 +664,19 @@ function MenuItem({
661
664
  </Animated.View>
662
665
  </AnimatedSurface>
663
666
  <View
664
- key={JSON.stringify([item.label, fontScale, maxWidth, theme.fonts.titleMedium])}
667
+ key={JSON.stringify([item.label, fontScale, maxWidth, iconSpace, theme.fonts.titleMedium])}
665
668
  pointerEvents="none"
666
669
  accessibilityElementsHidden
667
670
  importantForAccessibility="no-hide-descendants"
668
671
  {...(Platform.OS === 'web' ? { 'aria-hidden': true } : {})}
669
- style={[styles.measure, { maxWidth: Math.max(1, maxWidth - 48 - (item.icon ? 32 : 0)) }]}
672
+ style={[styles.measure, { maxWidth: Math.max(1, maxWidth - 48 - iconSpace) }]}
670
673
  >
671
674
  <Text
672
675
  variant="titleMedium"
673
676
  onLayout={
674
677
  Platform.OS === 'web'
675
678
  ? (event) => {
676
- setWidth(Math.ceil(event.nativeEvent.layout.width) + 49 + (item.icon ? 32 : 0));
679
+ setLabelWidth(Math.ceil(event.nativeEvent.layout.width));
677
680
  setHeight(Math.max(56, Math.ceil(event.nativeEvent.layout.height) + 16));
678
681
  }
679
682
  : undefined
@@ -681,11 +684,7 @@ function MenuItem({
681
684
  onTextLayout={
682
685
  Platform.OS !== 'web'
683
686
  ? (event) => {
684
- setWidth(
685
- Math.ceil(Math.max(0, ...event.nativeEvent.lines.map((line) => line.width))) +
686
- 49 +
687
- (item.icon ? 32 : 0)
688
- );
687
+ setLabelWidth(Math.ceil(Math.max(0, ...event.nativeEvent.lines.map((line) => line.width))));
689
688
  setHeight(
690
689
  Math.max(56, Math.ceil(event.nativeEvent.lines.reduce((sum, line) => sum + line.height, 0)) + 16)
691
690
  );
@@ -41,6 +41,8 @@ export interface TextFieldProps extends Omit<TextInputProps, 'style' | 'value' |
41
41
  value: string;
42
42
  onChangeText: (value: string) => void;
43
43
  variant?: 'filled' | 'outlined';
44
+ /** Compact starts at 48 dp. Both sizes grow with text scaling and multiline content. */
45
+ size?: 'standard' | 'compact';
44
46
  label?: string;
45
47
  disabled?: boolean;
46
48
  readOnly?: boolean;
@@ -83,6 +85,7 @@ export const TextField = forwardRef<TextFieldHandle, TextFieldProps>(function Te
83
85
  value,
84
86
  onChangeText,
85
87
  variant = 'filled',
88
+ size = 'standard',
86
89
  label,
87
90
  disabled = false,
88
91
  readOnly = false,
@@ -209,7 +212,15 @@ export const TextField = forwardRef<TextFieldHandle, TextFieldProps>(function Te
209
212
  ) : null);
210
213
  const labelStart = leadingContent ? 52 : 16;
211
214
  const lineHeight = 24 * fontScale;
212
- const minimumHeight = Math.max(56, label && !outlined ? 16 + 40 * fontScale : 32 + lineHeight);
215
+ const compact = size === 'compact';
216
+ const verticalPadding = compact ? 12 : 16;
217
+ const filledLabelPadding = verticalPadding - 8;
218
+ const hasFilledLabel = Boolean(label) && !outlined;
219
+ const paddingTop = hasFilledLabel ? filledLabelPadding + 16 * fontScale : verticalPadding;
220
+ const paddingBottom = hasFilledLabel ? filledLabelPadding : verticalPadding;
221
+ const minimumHeight = Math.max(compact ? 48 : 56, paddingTop + lineHeight + paddingBottom);
222
+ const labelTop = outlined ? verticalPadding : filledLabelPadding + 8 * fontScale;
223
+ const labelTravel = outlined ? labelTop + 8 * fontScale : 8 * fontScale;
213
224
 
214
225
  // RNW reports scrollHeight including the previous minimum height. Measure the
215
226
  // natural textarea synchronously, restoring its style before the next paint,
@@ -315,7 +326,7 @@ export const TextField = forwardRef<TextFieldHandle, TextFieldProps>(function Te
315
326
  left: direction === 'rtl' ? undefined : labelStart + (outlined ? (16 - labelStart) * progress.get() - 4 : 0),
316
327
  right: direction === 'rtl' ? labelStart + (outlined ? (16 - labelStart) * progress.get() - 4 : 0) : undefined,
317
328
  backgroundColor: outlined && progress.get() > 0.001 ? fieldColor : 'transparent',
318
- transform: [{ translateY: outlined ? -(16 + 8 * fontScale) * progress.get() : -8 * fontScale * progress.get() }],
329
+ transform: [{ translateY: -labelTravel * progress.get() }],
319
330
  }));
320
331
  const focusInput = () => {
321
332
  // Read-only fields remain focusable for selecting and copying text.
@@ -391,8 +402,8 @@ export const TextField = forwardRef<TextFieldHandle, TextFieldProps>(function Te
391
402
  flexDirection: direction === 'rtl' ? 'row-reverse' : 'row',
392
403
  paddingLeft: (direction === 'rtl' ? trailingContent : leadingContent) ? 4 : 16,
393
404
  paddingRight: (direction === 'rtl' ? leadingContent : trailingContent) ? 4 : 16,
394
- paddingTop: label && !outlined ? 8 + 16 * fontScale : 16,
395
- paddingBottom: label && !outlined ? 8 : 16,
405
+ paddingTop,
406
+ paddingBottom,
396
407
  },
397
408
  ]}
398
409
  >
@@ -537,7 +548,7 @@ export const TextField = forwardRef<TextFieldHandle, TextFieldProps>(function Te
537
548
  style={[
538
549
  styles.label,
539
550
  {
540
- top: outlined ? 16 : 8 + 8 * fontScale,
551
+ top: labelTop,
541
552
  paddingHorizontal: outlined ? 4 : 0,
542
553
  maxWidth: trailingContent ? '70%' : '85%',
543
554
  },