@ankhorage/zora 1.5.0 → 1.5.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 07e9d96: Improve realistic example app chrome by adding compact AppBars with dark-mode toggles, applying semantic Screen backgrounds, and fixing native ZoraTabBar icon/label rendering.
8
+
3
9
  ## 1.5.0
4
10
 
5
11
  ### Minor Changes
@@ -1 +1 @@
1
- {"version":3,"file":"Screen.d.ts","sourceRoot":"","sources":["../../../src/layout/screen/Screen.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AA2B3C,eAAO,MAAM,MAAM,mDAAkC,CAAC"}
1
+ {"version":3,"file":"Screen.d.ts","sourceRoot":"","sources":["../../../src/layout/screen/Screen.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAmC3C,eAAO,MAAM,MAAM,mDAAkC,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { ScrollArea } from '@ankhorage/surface';
2
2
  import React from 'react';
3
- import { Container, Stack } from '../../foundation';
3
+ import { Box, Container, Stack } from '../../foundation';
4
4
  import { resolvePageMaxWidth } from '../../internal/recipes';
5
5
  import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
6
6
  function ScreenInner({ themeId: _themeId, mode: _mode, children, footer, scroll = true, width = 'default', testID, }) {
@@ -11,9 +11,13 @@ function ScreenInner({ themeId: _themeId, mode: _mode, children, footer, scroll
11
11
  </Stack>
12
12
  </Container>);
13
13
  if (!scroll) {
14
- return content;
14
+ return (<Box bg="background" flex={1}>
15
+ {content}
16
+ </Box>);
15
17
  }
16
- return <ScrollArea>{content}</ScrollArea>;
18
+ return (<ScrollArea bg="background" style={{ flex: 1 }}>
19
+ {content}
20
+ </ScrollArea>);
17
21
  }
18
22
  export const Screen = withZoraThemeScope(ScreenInner);
19
23
  //# sourceMappingURL=Screen.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Screen.js","sourceRoot":"","sources":["../../../src/layout/screen/Screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAGpE,SAAS,WAAW,CAAC,EACnB,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,KAAK,EACX,QAAQ,EACR,MAAM,EACN,MAAM,GAAG,IAAI,EACb,KAAK,GAAG,SAAS,EACjB,MAAM,GACM;IACZ,MAAM,OAAO,GAAG,CACd,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CACtE;MAAA,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CACZ;QAAA,CAAC,QAAQ,CACT;QAAA,CAAC,MAAM,CACT;MAAA,EAAE,KAAK,CACT;IAAA,EAAE,SAAS,CAAC,CACb,CAAC;IAEF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC","sourcesContent":["import { ScrollArea } from '@ankhorage/surface';\nimport React from 'react';\n\nimport { Container, Stack } from '../../foundation';\nimport { resolvePageMaxWidth } from '../../internal/recipes';\nimport { withZoraThemeScope } from '../../theme/withZoraThemeScope';\nimport type { ScreenProps } from './types';\n\nfunction ScreenInner({\n themeId: _themeId,\n mode: _mode,\n children,\n footer,\n scroll = true,\n width = 'default',\n testID,\n}: ScreenProps) {\n const content = (\n <Container maxWidth={resolvePageMaxWidth(width)} py=\"xl\" testID={testID}>\n <Stack gap=\"l\">\n {children}\n {footer}\n </Stack>\n </Container>\n );\n\n if (!scroll) {\n return content;\n }\n\n return <ScrollArea>{content}</ScrollArea>;\n}\n\nexport const Screen = withZoraThemeScope(ScreenInner);\n"]}
1
+ {"version":3,"file":"Screen.js","sourceRoot":"","sources":["../../../src/layout/screen/Screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAGpE,SAAS,WAAW,CAAC,EACnB,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,KAAK,EACX,QAAQ,EACR,MAAM,EACN,MAAM,GAAG,IAAI,EACb,KAAK,GAAG,SAAS,EACjB,MAAM,GACM;IACZ,MAAM,OAAO,GAAG,CACd,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CACtE;MAAA,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CACZ;QAAA,CAAC,QAAQ,CACT;QAAA,CAAC,MAAM,CACT;MAAA,EAAE,KAAK,CACT;IAAA,EAAE,SAAS,CAAC,CACb,CAAC;IAEF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CACL,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAC3B;QAAA,CAAC,OAAO,CACV;MAAA,EAAE,GAAG,CAAC,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,CAAC,UAAU,CAAC,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAC7C;MAAA,CAAC,OAAO,CACV;IAAA,EAAE,UAAU,CAAC,CACd,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC","sourcesContent":["import { ScrollArea } from '@ankhorage/surface';\nimport React from 'react';\n\nimport { Box, Container, Stack } from '../../foundation';\nimport { resolvePageMaxWidth } from '../../internal/recipes';\nimport { withZoraThemeScope } from '../../theme/withZoraThemeScope';\nimport type { ScreenProps } from './types';\n\nfunction ScreenInner({\n themeId: _themeId,\n mode: _mode,\n children,\n footer,\n scroll = true,\n width = 'default',\n testID,\n}: ScreenProps) {\n const content = (\n <Container maxWidth={resolvePageMaxWidth(width)} py=\"xl\" testID={testID}>\n <Stack gap=\"l\">\n {children}\n {footer}\n </Stack>\n </Container>\n );\n\n if (!scroll) {\n return (\n <Box bg=\"background\" flex={1}>\n {content}\n </Box>\n );\n }\n\n return (\n <ScrollArea bg=\"background\" style={{ flex: 1 }}>\n {content}\n </ScrollArea>\n );\n}\n\nexport const Screen = withZoraThemeScope(ScreenInner);\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ZoraTabBar.d.ts","sourceRoot":"","sources":["../../../src/patterns/zora-tab-bar/ZoraTabBar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAQ1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AA6C/C,eAAO,MAAM,UAAU,uDAAsC,CAAC"}
1
+ {"version":3,"file":"ZoraTabBar.d.ts","sourceRoot":"","sources":["../../../src/patterns/zora-tab-bar/ZoraTabBar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAW1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAoI/C,eAAO,MAAM,UAAU,uDAAsC,CAAC"}
@@ -1,27 +1,76 @@
1
- import { TabBar as SurfaceTabBar } from '@ankhorage/surface';
2
1
  import React from 'react';
3
- import { Surface } from '../../foundation';
2
+ import { Pressable, Text as ReactNativeText } from 'react-native';
3
+ import { Icon } from '../../components/icon';
4
+ import { Box, Surface } from '../../foundation';
4
5
  import { createTabBarItemPressHandler, resolveNavigationItems, } from '../../internal/resolveZoraNavigationItems';
6
+ import { useZoraTheme } from '../../theme/useZoraTheme';
5
7
  import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
6
- function ZoraTabBarInner({ themeId: _themeId, mode: _mode, state, navigation, descriptors, routeMap, compact = false, chrome = 'raised', testID, }) {
8
+ function resolveAccessibilityLabel(label, explicitLabel) {
9
+ if (explicitLabel !== undefined) {
10
+ return explicitLabel;
11
+ }
12
+ if (typeof label === 'string') {
13
+ return label;
14
+ }
15
+ if (typeof label === 'number') {
16
+ return String(label);
17
+ }
18
+ return undefined;
19
+ }
20
+ function ZoraTabBarInner({ themeId: _themeId, mode: _mode, state, navigation, descriptors, insets, routeMap, compact = false, chrome = 'raised', testID, }) {
21
+ const { theme } = useZoraTheme();
7
22
  const resolved = resolveNavigationItems({
8
23
  state,
9
24
  descriptors,
10
25
  routeMap,
11
26
  kind: 'tab',
12
27
  });
13
- const items = resolved.map((item) => ({
14
- id: item.route.key,
15
- label: item.label,
16
- icon: item.metadata?.icon,
17
- badge: item.metadata?.badge,
18
- active: item.active,
19
- disabled: item.disabled,
20
- onPress: createTabBarItemPressHandler({ item, navigation }),
21
- accessibilityLabel: item.metadata?.accessibilityLabel,
22
- testID: item.metadata?.testID,
23
- }));
24
- const content = <SurfaceTabBar compact={compact} items={items} testID={testID}/>;
28
+ const bottomInset = insets?.bottom ?? 0;
29
+ const minHeight = compact ? 56 : 64;
30
+ const labelSize = compact ? theme.typography.sizes.xs : theme.typography.sizes.s;
31
+ const labelWeight = theme.typography.weights.medium;
32
+ const content = (<Box bg="surface" style={{
33
+ borderTopColor: theme.semantics.border.default,
34
+ borderTopWidth: 1,
35
+ flexDirection: 'row',
36
+ minHeight: minHeight + bottomInset,
37
+ paddingBottom: bottomInset,
38
+ }} testID={testID}>
39
+ {resolved.map((item) => {
40
+ const { active } = item;
41
+ const { disabled } = item;
42
+ const contentColor = disabled
43
+ ? theme.semantics.content.subtle
44
+ : active
45
+ ? theme.semantics.action.primary.base
46
+ : theme.semantics.content.muted;
47
+ const backgroundColor = active
48
+ ? theme.semantics.action.primary.softBg
49
+ : theme.semantics.surface.default;
50
+ return (<Pressable accessibilityLabel={resolveAccessibilityLabel(item.label, item.metadata?.accessibilityLabel)} accessibilityRole="tab" accessibilityState={{ selected: active, disabled }} disabled={disabled} key={item.route.key} onPress={createTabBarItemPressHandler({ item, navigation })} style={{
51
+ alignItems: 'center',
52
+ backgroundColor,
53
+ flex: 1,
54
+ justifyContent: 'center',
55
+ minHeight,
56
+ opacity: disabled ? 0.48 : 1,
57
+ paddingHorizontal: theme.spacing.s,
58
+ paddingVertical: compact ? theme.spacing.xs : theme.spacing.s,
59
+ }} testID={item.metadata?.testID ?? (testID ? `${testID}-item-${item.route.key}` : undefined)}>
60
+ {item.metadata?.icon ? (<Icon color={contentColor} name={item.metadata.icon.name} provider={item.metadata.icon.provider} size={compact ? theme.spacing.m : theme.spacing.l}/>) : null}
61
+ <ReactNativeText numberOfLines={1} style={{
62
+ color: contentColor,
63
+ fontSize: labelSize,
64
+ fontWeight: labelWeight,
65
+ lineHeight: compact ? 16 : 20,
66
+ marginTop: item.metadata?.icon ? theme.spacing.xs : 0,
67
+ textAlign: 'center',
68
+ }}>
69
+ {item.label}
70
+ </ReactNativeText>
71
+ </Pressable>);
72
+ })}
73
+ </Box>);
25
74
  if (chrome === 'none') {
26
75
  return content;
27
76
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ZoraTabBar.js","sourceRoot":"","sources":["../../../src/patterns/zora-tab-bar/ZoraTabBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,GACvB,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAGpE,SAAS,eAAe,CAAC,EACvB,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,KAAK,EACX,KAAK,EACL,UAAU,EACV,WAAW,EACX,QAAQ,EACR,OAAO,GAAG,KAAK,EACf,MAAM,GAAG,QAAQ,EACjB,MAAM,GACU;IAChB,MAAM,QAAQ,GAAG,sBAAsB,CAAC;QACtC,KAAK;QACL,WAAW;QACX,QAAQ;QACR,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACpC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG;QAClB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI;QACzB,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK;QAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,OAAO,EAAE,4BAA4B,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;QAC3D,kBAAkB,EAAE,IAAI,CAAC,QAAQ,EAAE,kBAAkB;QACrD,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM;KAC9B,CAAC,CAAC,CAAC;IAEJ,MAAM,OAAO,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAG,CAAC;IAElF,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,CACL,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CACxE;MAAA,CAAC,OAAO,CACV;IAAA,EAAE,OAAO,CAAC,CACX,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,kBAAkB,CAAC,eAAe,CAAC,CAAC","sourcesContent":["import { TabBar as SurfaceTabBar } from '@ankhorage/surface';\nimport React from 'react';\n\nimport { Surface } from '../../foundation';\nimport {\n createTabBarItemPressHandler,\n resolveNavigationItems,\n} from '../../internal/resolveZoraNavigationItems';\nimport { withZoraThemeScope } from '../../theme/withZoraThemeScope';\nimport type { ZoraTabBarProps } from './types';\n\nfunction ZoraTabBarInner({\n themeId: _themeId,\n mode: _mode,\n state,\n navigation,\n descriptors,\n routeMap,\n compact = false,\n chrome = 'raised',\n testID,\n}: ZoraTabBarProps) {\n const resolved = resolveNavigationItems({\n state,\n descriptors,\n routeMap,\n kind: 'tab',\n });\n\n const items = resolved.map((item) => ({\n id: item.route.key,\n label: item.label,\n icon: item.metadata?.icon,\n badge: item.metadata?.badge,\n active: item.active,\n disabled: item.disabled,\n onPress: createTabBarItemPressHandler({ item, navigation }),\n accessibilityLabel: item.metadata?.accessibilityLabel,\n testID: item.metadata?.testID,\n }));\n\n const content = <SurfaceTabBar compact={compact} items={items} testID={testID} />;\n\n if (chrome === 'none') {\n return content;\n }\n\n return (\n <Surface variant=\"raised\" testID={testID ? `${testID}-chrome` : undefined}>\n {content}\n </Surface>\n );\n}\n\nexport const ZoraTabBar = withZoraThemeScope(ZoraTabBarInner);\n"]}
1
+ {"version":3,"file":"ZoraTabBar.js","sourceRoot":"","sources":["../../../src/patterns/zora-tab-bar/ZoraTabBar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,IAAI,IAAI,eAAe,EAAE,MAAM,cAAc,CAAC;AAElE,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,GACvB,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAGpE,SAAS,yBAAyB,CAChC,KAAsB,EACtB,aAAsB;IAEtB,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,eAAe,CAAC,EACvB,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,KAAK,EACX,KAAK,EACL,UAAU,EACV,WAAW,EACX,MAAM,EACN,QAAQ,EACR,OAAO,GAAG,KAAK,EACf,MAAM,GAAG,QAAQ,EACjB,MAAM,GACU;IAChB,MAAM,EAAE,KAAK,EAAE,GAAG,YAAY,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAG,sBAAsB,CAAC;QACtC,KAAK;QACL,WAAW;QACX,QAAQ;QACR,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,MAAM,EAAE,MAAM,IAAI,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACpC,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IACjF,MAAM,WAAW,GAAG,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC;IACpD,MAAM,OAAO,GAAG,CACd,CAAC,GAAG,CACF,EAAE,CAAC,SAAS,CACZ,KAAK,CAAC,CAAC;YACL,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO;YAC9C,cAAc,EAAE,CAAC;YACjB,aAAa,EAAE,KAAK;YACpB,SAAS,EAAE,SAAS,GAAG,WAAW;YAClC,aAAa,EAAE,WAAW;SAC3B,CAAC,CACF,MAAM,CAAC,CAAC,MAAM,CAAC,CAEf;MAAA,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACrB,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;YACxB,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;YAC1B,MAAM,YAAY,GAAG,QAAQ;gBAC3B,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM;gBAChC,CAAC,CAAC,MAAM;oBACN,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI;oBACrC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC;YACpC,MAAM,eAAe,GAAG,MAAM;gBAC5B,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM;gBACvC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC;YAEpC,OAAO,CACL,CAAC,SAAS,CACR,kBAAkB,CAAC,CAAC,yBAAyB,CAC3C,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAClC,CAAC,CACF,iBAAiB,CAAC,KAAK,CACvB,kBAAkB,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CACnD,QAAQ,CAAC,CAAC,QAAQ,CAAC,CACnB,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CACpB,OAAO,CAAC,CAAC,4BAA4B,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,CAC5D,KAAK,CAAC,CAAC;oBACL,UAAU,EAAE,QAAQ;oBACpB,eAAe;oBACf,IAAI,EAAE,CAAC;oBACP,cAAc,EAAE,QAAQ;oBACxB,SAAS;oBACT,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;oBAC5B,iBAAiB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;oBAClC,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;iBAC9D,CAAC,CACF,MAAM,CAAC,CACL,IAAI,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,SAAS,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CACnF,CAAC,CAED;YAAA,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CACrB,CAAC,IAAI,CACH,KAAK,CAAC,CAAC,YAAY,CAAC,CACpB,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAC9B,QAAQ,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CACtC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAClD,CACH,CAAC,CAAC,CAAC,IAAI,CACR;YAAA,CAAC,eAAe,CACd,aAAa,CAAC,CAAC,CAAC,CAAC,CACjB,KAAK,CAAC,CAAC;oBACL,KAAK,EAAE,YAAY;oBACnB,QAAQ,EAAE,SAAS;oBACnB,UAAU,EAAE,WAAW;oBACvB,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;oBAC7B,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;oBACrD,SAAS,EAAE,QAAQ;iBACpB,CAAC,CAEF;cAAA,CAAC,IAAI,CAAC,KAAK,CACb;YAAA,EAAE,eAAe,CACnB;UAAA,EAAE,SAAS,CAAC,CACb,CAAC;QACJ,CAAC,CAAC,CACJ;IAAA,EAAE,GAAG,CAAC,CACP,CAAC;IAEF,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,CACL,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CACxE;MAAA,CAAC,OAAO,CACV;IAAA,EAAE,OAAO,CAAC,CACX,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,kBAAkB,CAAC,eAAe,CAAC,CAAC","sourcesContent":["import React from 'react';\nimport { Pressable, Text as ReactNativeText } from 'react-native';\n\nimport { Icon } from '../../components/icon';\nimport { Box, Surface } from '../../foundation';\nimport {\n createTabBarItemPressHandler,\n resolveNavigationItems,\n} from '../../internal/resolveZoraNavigationItems';\nimport { useZoraTheme } from '../../theme/useZoraTheme';\nimport { withZoraThemeScope } from '../../theme/withZoraThemeScope';\nimport type { ZoraTabBarProps } from './types';\n\nfunction resolveAccessibilityLabel(\n label: React.ReactNode,\n explicitLabel?: string,\n): string | undefined {\n if (explicitLabel !== undefined) {\n return explicitLabel;\n }\n\n if (typeof label === 'string') {\n return label;\n }\n\n if (typeof label === 'number') {\n return String(label);\n }\n\n return undefined;\n}\n\nfunction ZoraTabBarInner({\n themeId: _themeId,\n mode: _mode,\n state,\n navigation,\n descriptors,\n insets,\n routeMap,\n compact = false,\n chrome = 'raised',\n testID,\n}: ZoraTabBarProps) {\n const { theme } = useZoraTheme();\n const resolved = resolveNavigationItems({\n state,\n descriptors,\n routeMap,\n kind: 'tab',\n });\n\n const bottomInset = insets?.bottom ?? 0;\n const minHeight = compact ? 56 : 64;\n const labelSize = compact ? theme.typography.sizes.xs : theme.typography.sizes.s;\n const labelWeight = theme.typography.weights.medium;\n const content = (\n <Box\n bg=\"surface\"\n style={{\n borderTopColor: theme.semantics.border.default,\n borderTopWidth: 1,\n flexDirection: 'row',\n minHeight: minHeight + bottomInset,\n paddingBottom: bottomInset,\n }}\n testID={testID}\n >\n {resolved.map((item) => {\n const { active } = item;\n const { disabled } = item;\n const contentColor = disabled\n ? theme.semantics.content.subtle\n : active\n ? theme.semantics.action.primary.base\n : theme.semantics.content.muted;\n const backgroundColor = active\n ? theme.semantics.action.primary.softBg\n : theme.semantics.surface.default;\n\n return (\n <Pressable\n accessibilityLabel={resolveAccessibilityLabel(\n item.label,\n item.metadata?.accessibilityLabel,\n )}\n accessibilityRole=\"tab\"\n accessibilityState={{ selected: active, disabled }}\n disabled={disabled}\n key={item.route.key}\n onPress={createTabBarItemPressHandler({ item, navigation })}\n style={{\n alignItems: 'center',\n backgroundColor,\n flex: 1,\n justifyContent: 'center',\n minHeight,\n opacity: disabled ? 0.48 : 1,\n paddingHorizontal: theme.spacing.s,\n paddingVertical: compact ? theme.spacing.xs : theme.spacing.s,\n }}\n testID={\n item.metadata?.testID ?? (testID ? `${testID}-item-${item.route.key}` : undefined)\n }\n >\n {item.metadata?.icon ? (\n <Icon\n color={contentColor}\n name={item.metadata.icon.name}\n provider={item.metadata.icon.provider}\n size={compact ? theme.spacing.m : theme.spacing.l}\n />\n ) : null}\n <ReactNativeText\n numberOfLines={1}\n style={{\n color: contentColor,\n fontSize: labelSize,\n fontWeight: labelWeight,\n lineHeight: compact ? 16 : 20,\n marginTop: item.metadata?.icon ? theme.spacing.xs : 0,\n textAlign: 'center',\n }}\n >\n {item.label}\n </ReactNativeText>\n </Pressable>\n );\n })}\n </Box>\n );\n\n if (chrome === 'none') {\n return content;\n }\n\n return (\n <Surface variant=\"raised\" testID={testID ? `${testID}-chrome` : undefined}>\n {content}\n </Surface>\n );\n}\n\nexport const ZoraTabBar = withZoraThemeScope(ZoraTabBarInner);\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ankhorage/zora",
3
3
  "type": "module",
4
- "version": "1.5.0",
4
+ "version": "1.5.1",
5
5
  "description": "Opinionated React Native and React Native Web UI kit built on @ankhorage/surface.",
6
6
  "homepage": "https://github.com/ankhorage/zora#readme",
7
7
  "bugs": {
@@ -1,7 +1,7 @@
1
1
  import { ScrollArea } from '@ankhorage/surface';
2
2
  import React from 'react';
3
3
 
4
- import { Container, Stack } from '../../foundation';
4
+ import { Box, Container, Stack } from '../../foundation';
5
5
  import { resolvePageMaxWidth } from '../../internal/recipes';
6
6
  import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
7
7
  import type { ScreenProps } from './types';
@@ -25,10 +25,18 @@ function ScreenInner({
25
25
  );
26
26
 
27
27
  if (!scroll) {
28
- return content;
28
+ return (
29
+ <Box bg="background" flex={1}>
30
+ {content}
31
+ </Box>
32
+ );
29
33
  }
30
34
 
31
- return <ScrollArea>{content}</ScrollArea>;
35
+ return (
36
+ <ScrollArea bg="background" style={{ flex: 1 }}>
37
+ {content}
38
+ </ScrollArea>
39
+ );
32
40
  }
33
41
 
34
42
  export const Screen = withZoraThemeScope(ScreenInner);
@@ -1,25 +1,48 @@
1
- import { TabBar as SurfaceTabBar } from '@ankhorage/surface';
2
1
  import React from 'react';
2
+ import { Pressable, Text as ReactNativeText } from 'react-native';
3
3
 
4
- import { Surface } from '../../foundation';
4
+ import { Icon } from '../../components/icon';
5
+ import { Box, Surface } from '../../foundation';
5
6
  import {
6
7
  createTabBarItemPressHandler,
7
8
  resolveNavigationItems,
8
9
  } from '../../internal/resolveZoraNavigationItems';
10
+ import { useZoraTheme } from '../../theme/useZoraTheme';
9
11
  import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
10
12
  import type { ZoraTabBarProps } from './types';
11
13
 
14
+ function resolveAccessibilityLabel(
15
+ label: React.ReactNode,
16
+ explicitLabel?: string,
17
+ ): string | undefined {
18
+ if (explicitLabel !== undefined) {
19
+ return explicitLabel;
20
+ }
21
+
22
+ if (typeof label === 'string') {
23
+ return label;
24
+ }
25
+
26
+ if (typeof label === 'number') {
27
+ return String(label);
28
+ }
29
+
30
+ return undefined;
31
+ }
32
+
12
33
  function ZoraTabBarInner({
13
34
  themeId: _themeId,
14
35
  mode: _mode,
15
36
  state,
16
37
  navigation,
17
38
  descriptors,
39
+ insets,
18
40
  routeMap,
19
41
  compact = false,
20
42
  chrome = 'raised',
21
43
  testID,
22
44
  }: ZoraTabBarProps) {
45
+ const { theme } = useZoraTheme();
23
46
  const resolved = resolveNavigationItems({
24
47
  state,
25
48
  descriptors,
@@ -27,19 +50,85 @@ function ZoraTabBarInner({
27
50
  kind: 'tab',
28
51
  });
29
52
 
30
- const items = resolved.map((item) => ({
31
- id: item.route.key,
32
- label: item.label,
33
- icon: item.metadata?.icon,
34
- badge: item.metadata?.badge,
35
- active: item.active,
36
- disabled: item.disabled,
37
- onPress: createTabBarItemPressHandler({ item, navigation }),
38
- accessibilityLabel: item.metadata?.accessibilityLabel,
39
- testID: item.metadata?.testID,
40
- }));
41
-
42
- const content = <SurfaceTabBar compact={compact} items={items} testID={testID} />;
53
+ const bottomInset = insets?.bottom ?? 0;
54
+ const minHeight = compact ? 56 : 64;
55
+ const labelSize = compact ? theme.typography.sizes.xs : theme.typography.sizes.s;
56
+ const labelWeight = theme.typography.weights.medium;
57
+ const content = (
58
+ <Box
59
+ bg="surface"
60
+ style={{
61
+ borderTopColor: theme.semantics.border.default,
62
+ borderTopWidth: 1,
63
+ flexDirection: 'row',
64
+ minHeight: minHeight + bottomInset,
65
+ paddingBottom: bottomInset,
66
+ }}
67
+ testID={testID}
68
+ >
69
+ {resolved.map((item) => {
70
+ const { active } = item;
71
+ const { disabled } = item;
72
+ const contentColor = disabled
73
+ ? theme.semantics.content.subtle
74
+ : active
75
+ ? theme.semantics.action.primary.base
76
+ : theme.semantics.content.muted;
77
+ const backgroundColor = active
78
+ ? theme.semantics.action.primary.softBg
79
+ : theme.semantics.surface.default;
80
+
81
+ return (
82
+ <Pressable
83
+ accessibilityLabel={resolveAccessibilityLabel(
84
+ item.label,
85
+ item.metadata?.accessibilityLabel,
86
+ )}
87
+ accessibilityRole="tab"
88
+ accessibilityState={{ selected: active, disabled }}
89
+ disabled={disabled}
90
+ key={item.route.key}
91
+ onPress={createTabBarItemPressHandler({ item, navigation })}
92
+ style={{
93
+ alignItems: 'center',
94
+ backgroundColor,
95
+ flex: 1,
96
+ justifyContent: 'center',
97
+ minHeight,
98
+ opacity: disabled ? 0.48 : 1,
99
+ paddingHorizontal: theme.spacing.s,
100
+ paddingVertical: compact ? theme.spacing.xs : theme.spacing.s,
101
+ }}
102
+ testID={
103
+ item.metadata?.testID ?? (testID ? `${testID}-item-${item.route.key}` : undefined)
104
+ }
105
+ >
106
+ {item.metadata?.icon ? (
107
+ <Icon
108
+ color={contentColor}
109
+ name={item.metadata.icon.name}
110
+ provider={item.metadata.icon.provider}
111
+ size={compact ? theme.spacing.m : theme.spacing.l}
112
+ />
113
+ ) : null}
114
+ <ReactNativeText
115
+ numberOfLines={1}
116
+ style={{
117
+ color: contentColor,
118
+ fontSize: labelSize,
119
+ fontWeight: labelWeight,
120
+ lineHeight: compact ? 16 : 20,
121
+ marginTop: item.metadata?.icon ? theme.spacing.xs : 0,
122
+ textAlign: 'center',
123
+ }}
124
+ >
125
+ {item.label}
126
+ </ReactNativeText>
127
+ </Pressable>
128
+ );
129
+ })}
130
+ </Box>
131
+ );
43
132
 
44
133
  if (chrome === 'none') {
45
134
  return content;