@onlynative/components 0.1.0 → 0.1.1-alpha.1

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.
Files changed (70) hide show
  1. package/dist/appbar/index.js +133 -62
  2. package/dist/button/index.js +125 -33
  3. package/dist/card/index.js +88 -20
  4. package/dist/checkbox/index.js +88 -17
  5. package/dist/chip/index.js +122 -30
  6. package/dist/icon-button/index.js +107 -36
  7. package/dist/index.js +335 -251
  8. package/dist/list/index.js +71 -24
  9. package/dist/radio/index.js +43 -14
  10. package/dist/switch/index.js +90 -19
  11. package/dist/text-field/index.js +82 -26
  12. package/package.json +4 -23
  13. package/src/appbar/AppBar.tsx +0 -302
  14. package/src/appbar/index.ts +0 -2
  15. package/src/appbar/styles.ts +0 -92
  16. package/src/appbar/types.ts +0 -67
  17. package/src/button/Button.tsx +0 -133
  18. package/src/button/index.ts +0 -2
  19. package/src/button/styles.ts +0 -287
  20. package/src/button/types.ts +0 -42
  21. package/src/card/Card.tsx +0 -69
  22. package/src/card/index.ts +0 -2
  23. package/src/card/styles.ts +0 -150
  24. package/src/card/types.ts +0 -27
  25. package/src/checkbox/Checkbox.tsx +0 -113
  26. package/src/checkbox/index.ts +0 -2
  27. package/src/checkbox/styles.ts +0 -155
  28. package/src/checkbox/types.ts +0 -20
  29. package/src/chip/Chip.tsx +0 -188
  30. package/src/chip/index.ts +0 -2
  31. package/src/chip/styles.ts +0 -239
  32. package/src/chip/types.ts +0 -58
  33. package/src/icon-button/IconButton.tsx +0 -362
  34. package/src/icon-button/index.ts +0 -6
  35. package/src/icon-button/styles.ts +0 -259
  36. package/src/icon-button/types.ts +0 -55
  37. package/src/index.ts +0 -54
  38. package/src/keyboard-avoiding-wrapper/KeyboardAvoidingWrapper.tsx +0 -69
  39. package/src/keyboard-avoiding-wrapper/index.ts +0 -2
  40. package/src/keyboard-avoiding-wrapper/styles.ts +0 -10
  41. package/src/keyboard-avoiding-wrapper/types.ts +0 -37
  42. package/src/layout/Box.tsx +0 -99
  43. package/src/layout/Column.tsx +0 -16
  44. package/src/layout/Grid.tsx +0 -49
  45. package/src/layout/Layout.tsx +0 -81
  46. package/src/layout/Row.tsx +0 -22
  47. package/src/layout/index.ts +0 -13
  48. package/src/layout/resolveSpacing.ts +0 -11
  49. package/src/layout/types.ts +0 -82
  50. package/src/list/List.tsx +0 -17
  51. package/src/list/ListDivider.tsx +0 -20
  52. package/src/list/ListItem.tsx +0 -128
  53. package/src/list/index.ts +0 -9
  54. package/src/list/styles.ts +0 -132
  55. package/src/list/types.ts +0 -54
  56. package/src/radio/Radio.tsx +0 -103
  57. package/src/radio/index.ts +0 -2
  58. package/src/radio/styles.ts +0 -139
  59. package/src/radio/types.ts +0 -20
  60. package/src/switch/Switch.tsx +0 -121
  61. package/src/switch/index.ts +0 -2
  62. package/src/switch/styles.ts +0 -172
  63. package/src/switch/types.ts +0 -32
  64. package/src/text-field/TextField.tsx +0 -301
  65. package/src/text-field/index.ts +0 -2
  66. package/src/text-field/styles.ts +0 -239
  67. package/src/text-field/types.ts +0 -49
  68. package/src/typography/Typography.tsx +0 -79
  69. package/src/typography/index.ts +0 -3
  70. package/src/typography/types.ts +0 -17
@@ -26,13 +26,69 @@ module.exports = __toCommonJS(text_field_exports);
26
26
 
27
27
  // src/text-field/TextField.tsx
28
28
  var import_react = require("react");
29
- var import_react_native2 = require("react-native");
29
+ var import_react_native4 = require("react-native");
30
30
  var import_core = require("@onlynative/core");
31
- var import_utils2 = require("@onlynative/utils");
32
31
 
33
- // src/text-field/styles.ts
32
+ // ../utils/dist/chunk-OQRDRRQA.mjs
33
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
34
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
35
+ }) : x)(function(x) {
36
+ if (typeof require !== "undefined") return require.apply(this, arguments);
37
+ throw Error('Dynamic require of "' + x + '" is not supported');
38
+ });
39
+
40
+ // ../utils/dist/index.mjs
34
41
  var import_react_native = require("react-native");
35
- var import_utils = require("@onlynative/utils");
42
+ var import_react_native2 = require("react-native");
43
+ function parseHexColor(color) {
44
+ const normalized = color.replace("#", "");
45
+ if (normalized.length !== 6 && normalized.length !== 8) {
46
+ return null;
47
+ }
48
+ const r = Number.parseInt(normalized.slice(0, 2), 16);
49
+ const g = Number.parseInt(normalized.slice(2, 4), 16);
50
+ const b = Number.parseInt(normalized.slice(4, 6), 16);
51
+ if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) {
52
+ return null;
53
+ }
54
+ return { r, g, b };
55
+ }
56
+ function clampAlpha(alpha) {
57
+ return Math.max(0, Math.min(1, alpha));
58
+ }
59
+ function alphaColor(color, alpha) {
60
+ const channels = parseHexColor(color);
61
+ const boundedAlpha = clampAlpha(alpha);
62
+ if (!channels) {
63
+ return color;
64
+ }
65
+ return `rgba(${channels.r}, ${channels.g}, ${channels.b}, ${boundedAlpha})`;
66
+ }
67
+ var _MCIcons = null;
68
+ var _resolved = false;
69
+ function getMaterialCommunityIcons() {
70
+ if (!_resolved) {
71
+ _resolved = true;
72
+ try {
73
+ const mod = __require("@expo/vector-icons/MaterialCommunityIcons");
74
+ _MCIcons = mod.default || mod;
75
+ } catch {
76
+ _MCIcons = null;
77
+ }
78
+ }
79
+ if (!_MCIcons) {
80
+ throw new Error(
81
+ "@expo/vector-icons is required for icon support. Install it with: npx expo install @expo/vector-icons"
82
+ );
83
+ }
84
+ return _MCIcons;
85
+ }
86
+ function transformOrigin(vertical = "top") {
87
+ return import_react_native2.I18nManager.isRTL ? `right ${vertical}` : `left ${vertical}`;
88
+ }
89
+
90
+ // src/text-field/styles.ts
91
+ var import_react_native3 = require("react-native");
36
92
  var CONTAINER_HEIGHT = 56;
37
93
  var ICON_SIZE = 24;
38
94
  var LABEL_FLOATED_LINE_HEIGHT = 16;
@@ -57,15 +113,15 @@ function getVariantColors(theme, variant) {
57
113
  focusedLabelColor: theme.colors.primary,
58
114
  errorLabelColor: theme.colors.error,
59
115
  textColor: theme.colors.onSurface,
60
- disabledTextColor: (0, import_utils.alphaColor)(theme.colors.onSurface, disabledOpacity),
61
- disabledLabelColor: (0, import_utils.alphaColor)(theme.colors.onSurface, disabledOpacity),
62
- disabledBorderColor: (0, import_utils.alphaColor)(theme.colors.onSurface, 0.12),
116
+ disabledTextColor: alphaColor(theme.colors.onSurface, disabledOpacity),
117
+ disabledLabelColor: alphaColor(theme.colors.onSurface, disabledOpacity),
118
+ disabledBorderColor: alphaColor(theme.colors.onSurface, 0.12),
63
119
  placeholderColor: theme.colors.onSurfaceVariant,
64
120
  supportingTextColor: theme.colors.onSurfaceVariant,
65
121
  errorSupportingTextColor: theme.colors.error,
66
122
  iconColor: theme.colors.onSurfaceVariant,
67
123
  errorIconColor: theme.colors.error,
68
- disabledIconColor: (0, import_utils.alphaColor)(theme.colors.onSurface, disabledOpacity)
124
+ disabledIconColor: alphaColor(theme.colors.onSurface, disabledOpacity)
69
125
  };
70
126
  if (variant === "outlined") {
71
127
  return {
@@ -80,7 +136,7 @@ function getVariantColors(theme, variant) {
80
136
  ...common,
81
137
  backgroundColor: theme.colors.surfaceContainerHighest,
82
138
  borderColor: theme.colors.onSurfaceVariant,
83
- disabledBackgroundColor: (0, import_utils.alphaColor)(theme.colors.onSurface, 0.04),
139
+ disabledBackgroundColor: alphaColor(theme.colors.onSurface, 0.04),
84
140
  labelColor: theme.colors.onSurfaceVariant
85
141
  };
86
142
  }
@@ -91,7 +147,7 @@ function createStyles(theme, variant) {
91
147
  const isFilled = variant === "filled";
92
148
  return {
93
149
  colors,
94
- styles: import_react_native.StyleSheet.create({
150
+ styles: import_react_native3.StyleSheet.create({
95
151
  root: {
96
152
  alignSelf: "stretch"
97
153
  },
@@ -162,7 +218,7 @@ function createStyles(theme, variant) {
162
218
  fontWeight: bodySmall.fontWeight,
163
219
  letterSpacing: bodySmall.letterSpacing,
164
220
  color: colors.labelColor,
165
- transformOrigin: (0, import_utils.transformOrigin)("top")
221
+ transformOrigin: transformOrigin("top")
166
222
  },
167
223
  labelNotch: {
168
224
  paddingHorizontal: 4
@@ -255,7 +311,7 @@ function TextField({
255
311
  const isError = Boolean(error) || Boolean(errorText);
256
312
  const isFilled = variant === "filled";
257
313
  const hasLeadingIcon = Boolean(leadingIcon);
258
- const MaterialCommunityIcons = leadingIcon || trailingIcon ? (0, import_utils2.getMaterialCommunityIcons)() : null;
314
+ const MaterialCommunityIcons = leadingIcon || trailingIcon ? getMaterialCommunityIcons() : null;
259
315
  const { colors, styles } = (0, import_react.useMemo)(
260
316
  () => createStyles(theme, variant),
261
317
  [theme, variant]
@@ -268,13 +324,13 @@ function TextField({
268
324
  const isControlled = value !== void 0;
269
325
  const hasValue = isControlled ? value !== "" : internalHasText;
270
326
  const isLabelFloated = isFocused || hasValue;
271
- const labelAnimRef = (0, import_react.useRef)(new import_react_native2.Animated.Value(isLabelFloated ? 1 : 0));
327
+ const labelAnimRef = (0, import_react.useRef)(new import_react_native4.Animated.Value(isLabelFloated ? 1 : 0));
272
328
  const labelAnim = labelAnimRef.current;
273
329
  (0, import_react.useEffect)(() => {
274
- import_react_native2.Animated.timing(labelAnim, {
330
+ import_react_native4.Animated.timing(labelAnim, {
275
331
  toValue: isLabelFloated ? 1 : 0,
276
332
  duration: 150,
277
- useNativeDriver: import_react_native2.Platform.OS !== "web"
333
+ useNativeDriver: import_react_native4.Platform.OS !== "web"
278
334
  }).start();
279
335
  }, [isLabelFloated, labelAnim]);
280
336
  const labelScale = (0, import_react.useMemo)(() => {
@@ -352,9 +408,9 @@ function TextField({
352
408
  [styles, isFocused, isError, isDisabled]
353
409
  );
354
410
  const displaySupportingText = isError ? errorText : supportingText;
355
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: [styles.root, style], children: [
356
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.Pressable, { onPress: handleContainerPress, disabled: isDisabled, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native2.View, { style: containerStyle, children: [
357
- leadingIcon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.leadingIcon, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
411
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native4.View, { style: [styles.root, style], children: [
412
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native4.Pressable, { onPress: handleContainerPress, disabled: isDisabled, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native4.View, { style: containerStyle, children: [
413
+ leadingIcon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native4.View, { style: styles.leadingIcon, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
358
414
  MaterialCommunityIcons,
359
415
  {
360
416
  name: leadingIcon,
@@ -363,14 +419,14 @@ function TextField({
363
419
  }
364
420
  ) }) : null,
365
421
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
366
- import_react_native2.View,
422
+ import_react_native4.View,
367
423
  {
368
424
  style: [
369
425
  styles.inputWrapper,
370
426
  label ? styles.inputWrapperWithLabel : void 0
371
427
  ],
372
428
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
373
- import_react_native2.TextInput,
429
+ import_react_native4.TextInput,
374
430
  {
375
431
  ref: inputRef,
376
432
  ...textInputProps,
@@ -396,14 +452,14 @@ function TextField({
396
452
  }
397
453
  ),
398
454
  trailingIcon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
399
- import_react_native2.Pressable,
455
+ import_react_native4.Pressable,
400
456
  {
401
457
  onPress: onTrailingIconPress,
402
458
  disabled: isDisabled || !onTrailingIconPress,
403
459
  accessibilityRole: "button",
404
460
  hitSlop: 12,
405
461
  style: styles.trailingIconPressable,
406
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.trailingIcon, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
462
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native4.View, { style: styles.trailingIcon, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
407
463
  MaterialCommunityIcons,
408
464
  {
409
465
  name: trailingIcon,
@@ -414,7 +470,7 @@ function TextField({
414
470
  }
415
471
  ) : null,
416
472
  label ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
417
- import_react_native2.Animated.Text,
473
+ import_react_native4.Animated.Text,
418
474
  {
419
475
  numberOfLines: 1,
420
476
  style: [
@@ -434,10 +490,10 @@ function TextField({
434
490
  children: label
435
491
  }
436
492
  ) : null,
437
- isFilled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: indicatorStyle }) : null
493
+ isFilled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native4.View, { style: indicatorStyle }) : null
438
494
  ] }) }),
439
- displaySupportingText ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: styles.supportingTextRow, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
440
- import_react_native2.Text,
495
+ displaySupportingText ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native4.View, { style: styles.supportingTextRow, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
496
+ import_react_native4.Text,
441
497
  {
442
498
  style: [
443
499
  styles.supportingText,
package/package.json CHANGED
@@ -1,83 +1,67 @@
1
1
  {
2
2
  "name": "@onlynative/components",
3
- "version": "0.1.0",
3
+ "version": "0.1.1-alpha.1",
4
4
  "description": "Material Design 3 UI components for React Native — Button, Card, Chip, TextField, and more.",
5
5
  "private": false,
6
6
  "sideEffects": false,
7
7
  "main": "dist/index.js",
8
8
  "module": "dist/index.js",
9
9
  "types": "dist/index.d.ts",
10
- "react-native": "src/index.ts",
11
- "source": "src/index.ts",
12
10
  "exports": {
13
11
  ".": {
14
12
  "types": "./dist/index.d.ts",
15
- "react-native": "./src/index.ts",
16
13
  "default": "./dist/index.js"
17
14
  },
18
15
  "./typography": {
19
16
  "types": "./dist/typography/index.d.ts",
20
- "react-native": "./src/typography/index.ts",
21
17
  "default": "./dist/typography/index.js"
22
18
  },
23
19
  "./layout": {
24
20
  "types": "./dist/layout/index.d.ts",
25
- "react-native": "./src/layout/index.ts",
26
21
  "default": "./dist/layout/index.js"
27
22
  },
28
23
  "./button": {
29
24
  "types": "./dist/button/index.d.ts",
30
- "react-native": "./src/button/index.ts",
31
25
  "default": "./dist/button/index.js"
32
26
  },
33
27
  "./icon-button": {
34
28
  "types": "./dist/icon-button/index.d.ts",
35
- "react-native": "./src/icon-button/index.ts",
36
29
  "default": "./dist/icon-button/index.js"
37
30
  },
38
31
  "./appbar": {
39
32
  "types": "./dist/appbar/index.d.ts",
40
- "react-native": "./src/appbar/index.ts",
41
33
  "default": "./dist/appbar/index.js"
42
34
  },
43
35
  "./card": {
44
36
  "types": "./dist/card/index.d.ts",
45
- "react-native": "./src/card/index.ts",
46
37
  "default": "./dist/card/index.js"
47
38
  },
48
39
  "./chip": {
49
40
  "types": "./dist/chip/index.d.ts",
50
- "react-native": "./src/chip/index.ts",
51
41
  "default": "./dist/chip/index.js"
52
42
  },
53
43
  "./checkbox": {
54
44
  "types": "./dist/checkbox/index.d.ts",
55
- "react-native": "./src/checkbox/index.ts",
56
45
  "default": "./dist/checkbox/index.js"
57
46
  },
58
47
  "./radio": {
59
48
  "types": "./dist/radio/index.d.ts",
60
- "react-native": "./src/radio/index.ts",
61
49
  "default": "./dist/radio/index.js"
62
50
  },
63
51
  "./switch": {
64
52
  "types": "./dist/switch/index.d.ts",
65
- "react-native": "./src/switch/index.ts",
66
53
  "default": "./dist/switch/index.js"
67
54
  },
68
55
  "./text-field": {
69
56
  "types": "./dist/text-field/index.d.ts",
70
- "react-native": "./src/text-field/index.ts",
71
57
  "default": "./dist/text-field/index.js"
72
58
  },
73
59
  "./list": {
74
60
  "types": "./dist/list/index.d.ts",
75
- "react-native": "./src/list/index.ts",
76
61
  "default": "./dist/list/index.js"
77
62
  },
78
63
  "./keyboard-avoiding-wrapper": {
79
64
  "types": "./dist/keyboard-avoiding-wrapper/index.d.ts",
80
- "react-native": "./src/keyboard-avoiding-wrapper/index.ts",
81
65
  "default": "./dist/keyboard-avoiding-wrapper/index.js"
82
66
  }
83
67
  },
@@ -129,9 +113,7 @@
129
113
  "provenance": true
130
114
  },
131
115
  "files": [
132
- "dist",
133
- "src",
134
- "!src/__tests__"
116
+ "dist"
135
117
  ],
136
118
  "license": "MIT",
137
119
  "repository": {
@@ -148,14 +130,13 @@
148
130
  "material-you"
149
131
  ],
150
132
  "scripts": {
151
- "build": "tsup src/index.ts src/typography/index.ts src/layout/index.ts src/button/index.ts src/icon-button/index.ts src/appbar/index.ts src/card/index.ts src/chip/index.ts src/checkbox/index.ts src/radio/index.ts src/switch/index.ts src/text-field/index.ts src/list/index.ts src/keyboard-avoiding-wrapper/index.ts --dts --format cjs --outDir dist --clean",
133
+ "build": "tsup",
152
134
  "typecheck": "tsc --noEmit",
153
135
  "test": "jest --passWithNoTests"
154
136
  },
155
137
  "peerDependencies": {
156
138
  "@expo/vector-icons": ">=14.0.0",
157
- "@onlynative/core": ">=0.1.0",
158
- "@onlynative/utils": ">=0.1.0-alpha.3",
139
+ "@onlynative/core": ">=0.1.1-alpha.1",
159
140
  "react": ">=18.0.0",
160
141
  "react-native": ">=0.72.0",
161
142
  "react-native-safe-area-context": ">=4.0.0"
@@ -1,302 +0,0 @@
1
- import { useCallback, useMemo, useState } from 'react'
2
- import type { ReactNode } from 'react'
3
- import type { LayoutChangeEvent, StyleProp, ViewStyle } from 'react-native'
4
- import { Platform, View } from 'react-native'
5
- import { SafeAreaView } from 'react-native-safe-area-context'
6
- import { defaultTopAppBarTokens, useTheme } from '@onlynative/core'
7
-
8
- import { IconButton } from '../icon-button'
9
- import type { IconButtonProps } from '../icon-button'
10
- import { Typography } from '../typography'
11
- import type { TypographyVariant } from '../typography'
12
- import { selectRTL } from '@onlynative/utils'
13
- import { createStyles } from './styles'
14
- import type { AppBarProps } from './types'
15
-
16
- type AppBarSize = 'small' | 'medium' | 'large'
17
- function getBackIcon(): IconButtonProps['icon'] {
18
- if (Platform.OS === 'ios') {
19
- return selectRTL('chevron-left', 'chevron-right')
20
- }
21
-
22
- return selectRTL('arrow-left', 'arrow-right')
23
- }
24
-
25
- const titleVariantBySize: Record<AppBarSize, TypographyVariant> = {
26
- small: 'titleLarge',
27
- medium: 'headlineSmall',
28
- large: 'headlineMedium',
29
- }
30
- const APP_BAR_TITLE_TEXT_PROPS = {
31
- numberOfLines: 1,
32
- ellipsizeMode: 'tail',
33
- accessibilityRole: 'header',
34
- } as const
35
-
36
- function resolveSize(variant: AppBarProps['variant']): AppBarSize {
37
- if (variant === 'medium' || variant === 'large') {
38
- return variant
39
- }
40
-
41
- return 'small'
42
- }
43
-
44
- function getSizeStyle(
45
- styles: ReturnType<typeof createStyles>,
46
- size: AppBarSize,
47
- ) {
48
- if (size === 'large') {
49
- return styles.largeContainer
50
- }
51
-
52
- return styles.mediumContainer
53
- }
54
-
55
- function withTopInset(
56
- enabled: boolean,
57
- content: ReactNode,
58
- style: StyleProp<ViewStyle>,
59
- ) {
60
- if (enabled) {
61
- return (
62
- <SafeAreaView edges={['top']} style={style}>
63
- {content}
64
- </SafeAreaView>
65
- )
66
- }
67
-
68
- return <View style={style}>{content}</View>
69
- }
70
-
71
- function measureWidth(event: LayoutChangeEvent): number {
72
- return Math.round(event.nativeEvent.layout.width)
73
- }
74
-
75
- export function AppBar({
76
- title,
77
- variant = 'small',
78
- canGoBack = false,
79
- onBackPress,
80
- insetTop = false,
81
- elevated = false,
82
- leading,
83
- trailing,
84
- actions,
85
- containerColor,
86
- contentColor,
87
- titleStyle,
88
- style,
89
- }: AppBarProps) {
90
- const theme = useTheme()
91
- const topAppBar = theme.topAppBar ?? defaultTopAppBarTokens
92
- const styles = useMemo(() => createStyles(theme), [theme])
93
- const [leadingWidth, setLeadingWidth] = useState(0)
94
- const [actionsWidth, setActionsWidth] = useState(0)
95
- const titleColorStyle = useMemo(
96
- () => ({ color: contentColor ?? theme.colors.onSurface }),
97
- [contentColor, theme.colors.onSurface],
98
- )
99
- const size = resolveSize(variant)
100
- const titleVariant = titleVariantBySize[size]
101
- const isCenterAligned = variant === 'center-aligned'
102
- const isExpanded = size !== 'small'
103
- const titleStartInset =
104
- topAppBar.horizontalPadding +
105
- Math.max(topAppBar.titleStartInset, leadingWidth)
106
- const compactTitleEndInset = topAppBar.horizontalPadding + actionsWidth
107
- const centeredSideInset =
108
- topAppBar.horizontalPadding + Math.max(leadingWidth, actionsWidth)
109
- const expandedTitleInsetStyle = useMemo<ViewStyle>(
110
- () => ({ paddingStart: titleStartInset }),
111
- [titleStartInset],
112
- )
113
- const overlayTitleInsetStyle = useMemo<ViewStyle>(
114
- () =>
115
- isCenterAligned
116
- ? { start: centeredSideInset, end: centeredSideInset }
117
- : { start: titleStartInset, end: compactTitleEndInset },
118
- [centeredSideInset, compactTitleEndInset, isCenterAligned, titleStartInset],
119
- )
120
-
121
- const leadingContent = useMemo(() => {
122
- if (leading) {
123
- return leading
124
- }
125
-
126
- if (!canGoBack) {
127
- return null
128
- }
129
-
130
- return (
131
- <View style={styles.iconFrame}>
132
- <IconButton
133
- icon={getBackIcon()}
134
- size="medium"
135
- variant="standard"
136
- iconColor={contentColor ?? theme.colors.onSurface}
137
- accessibilityLabel="Go back"
138
- onPress={onBackPress}
139
- />
140
- </View>
141
- )
142
- }, [
143
- canGoBack,
144
- contentColor,
145
- leading,
146
- onBackPress,
147
- styles.iconFrame,
148
- theme.colors.onSurface,
149
- ])
150
-
151
- const actionsContent = useMemo(() => {
152
- if (trailing) {
153
- return trailing
154
- }
155
-
156
- if (!actions || actions.length === 0) {
157
- return null
158
- }
159
-
160
- return (
161
- <View style={styles.actionsRow}>
162
- {actions.map((action, index) => (
163
- <View
164
- key={`${String(action.icon)}-${index}`}
165
- style={styles.iconFrame}
166
- >
167
- <IconButton
168
- icon={action.icon}
169
- size="medium"
170
- variant="standard"
171
- iconColor={contentColor}
172
- accessibilityLabel={action.accessibilityLabel}
173
- onPress={action.onPress}
174
- disabled={action.disabled}
175
- />
176
- </View>
177
- ))}
178
- </View>
179
- )
180
- }, [actions, contentColor, styles.actionsRow, styles.iconFrame, trailing])
181
-
182
- const onLeadingLayout = useCallback((event: LayoutChangeEvent) => {
183
- const nextWidth = measureWidth(event)
184
-
185
- setLeadingWidth((currentWidth) => {
186
- if (currentWidth === nextWidth) {
187
- return currentWidth
188
- }
189
-
190
- return nextWidth
191
- })
192
- }, [])
193
-
194
- const onActionsLayout = useCallback((event: LayoutChangeEvent) => {
195
- const nextWidth = measureWidth(event)
196
-
197
- setActionsWidth((currentWidth) => {
198
- if (currentWidth === nextWidth) {
199
- return currentWidth
200
- }
201
-
202
- return nextWidth
203
- })
204
- }, [])
205
-
206
- const topRow = (
207
- <View style={styles.topRow}>
208
- <View
209
- collapsable={false}
210
- onLayout={onLeadingLayout}
211
- style={styles.sideSlot}
212
- >
213
- {leadingContent}
214
- </View>
215
- <View style={styles.topRowSpacer} />
216
- <View
217
- collapsable={false}
218
- onLayout={onActionsLayout}
219
- style={styles.sideSlot}
220
- >
221
- {actionsContent}
222
- </View>
223
- </View>
224
- )
225
-
226
- const containerOverride = containerColor
227
- ? ({ backgroundColor: containerColor } as ViewStyle)
228
- : undefined
229
- const rootStyle: StyleProp<ViewStyle> = [
230
- styles.root,
231
- elevated ? styles.elevatedRoot : undefined,
232
- containerOverride,
233
- style,
234
- ]
235
- const safeAreaStyle: StyleProp<ViewStyle> = [
236
- styles.safeArea,
237
- elevated ? styles.elevatedSafeArea : undefined,
238
- containerOverride,
239
- ]
240
-
241
- if (isExpanded) {
242
- const content = (
243
- <View style={[styles.expandedContainer, getSizeStyle(styles, size)]}>
244
- {topRow}
245
- <View
246
- style={[
247
- styles.expandedTitleContainer,
248
- size === 'large'
249
- ? styles.largeTitlePadding
250
- : styles.mediumTitlePadding,
251
- expandedTitleInsetStyle,
252
- ]}
253
- >
254
- <Typography
255
- {...APP_BAR_TITLE_TEXT_PROPS}
256
- variant={titleVariant}
257
- style={[
258
- styles.title,
259
- titleColorStyle,
260
- styles.startAlignedTitle,
261
- titleStyle,
262
- ]}
263
- >
264
- {title}
265
- </Typography>
266
- </View>
267
- </View>
268
- )
269
-
270
- return (
271
- <View style={rootStyle}>
272
- {withTopInset(insetTop, content, safeAreaStyle)}
273
- </View>
274
- )
275
- }
276
-
277
- const content = (
278
- <View style={styles.smallContainer}>
279
- {topRow}
280
- <View style={[styles.overlayTitleContainer, overlayTitleInsetStyle]}>
281
- <Typography
282
- {...APP_BAR_TITLE_TEXT_PROPS}
283
- variant={titleVariant}
284
- style={[
285
- styles.title,
286
- titleColorStyle,
287
- isCenterAligned ? styles.centeredTitle : styles.startAlignedTitle,
288
- titleStyle,
289
- ]}
290
- >
291
- {title}
292
- </Typography>
293
- </View>
294
- </View>
295
- )
296
-
297
- return (
298
- <View style={rootStyle}>
299
- {withTopInset(insetTop, content, safeAreaStyle)}
300
- </View>
301
- )
302
- }
@@ -1,2 +0,0 @@
1
- export { AppBar } from './AppBar'
2
- export type { AppBarAction, AppBarProps, AppBarVariant } from './types'