@ankhorage/zora 2.13.2 → 3.0.0
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 +13 -0
- package/README.md +1 -1
- package/dist/components/action-sheet/ActionSheetItem.d.ts.map +1 -1
- package/dist/components/action-sheet/ActionSheetItem.js +1 -1
- package/dist/components/action-sheet/ActionSheetItem.js.map +1 -1
- package/dist/components/app-bar/AppBar.js.map +1 -1
- package/dist/components/avatar/Avatar.d.ts.map +1 -1
- package/dist/components/avatar/Avatar.js +1 -1
- package/dist/components/avatar/Avatar.js.map +1 -1
- package/dist/components/breadcrumbs/Breadcrumbs.d.ts.map +1 -1
- package/dist/components/breadcrumbs/Breadcrumbs.js +1 -1
- package/dist/components/breadcrumbs/Breadcrumbs.js.map +1 -1
- package/dist/components/chip/Chip.d.ts.map +1 -1
- package/dist/components/chip/Chip.js +1 -1
- package/dist/components/chip/Chip.js.map +1 -1
- package/dist/components/gradient/Gradient.d.ts +2 -2
- package/dist/components/gradient/Gradient.d.ts.map +1 -1
- package/dist/components/gradient/Gradient.js +12 -7
- package/dist/components/gradient/Gradient.js.map +1 -1
- package/dist/components/gradient/GradientRendererContext.d.ts +11 -0
- package/dist/components/gradient/GradientRendererContext.d.ts.map +1 -0
- package/dist/components/gradient/GradientRendererContext.js +19 -0
- package/dist/components/gradient/GradientRendererContext.js.map +1 -0
- package/dist/components/gradient/index.d.ts +2 -1
- package/dist/components/gradient/index.d.ts.map +1 -1
- package/dist/components/gradient/index.js +1 -0
- package/dist/components/gradient/index.js.map +1 -1
- package/dist/components/gradient/types.d.ts +14 -0
- package/dist/components/gradient/types.d.ts.map +1 -1
- package/dist/components/gradient/types.js.map +1 -1
- package/dist/components/icon/Icon.d.ts +1 -2
- package/dist/components/icon/Icon.d.ts.map +1 -1
- package/dist/components/icon/Icon.js.map +1 -1
- package/dist/components/input/Input.d.ts.map +1 -1
- package/dist/components/input/Input.js +1 -1
- package/dist/components/input/Input.js.map +1 -1
- package/dist/components/menu/Menu.d.ts.map +1 -1
- package/dist/components/menu/Menu.js +1 -1
- package/dist/components/menu/Menu.js.map +1 -1
- package/dist/components/metric-card/MetricCard.d.ts.map +1 -1
- package/dist/components/metric-card/MetricCard.js +1 -1
- package/dist/components/metric-card/MetricCard.js.map +1 -1
- package/dist/components/select/Select.js +1 -1
- package/dist/components/select/Select.js.map +1 -1
- package/dist/components/textarea/Textarea.d.ts.map +1 -1
- package/dist/components/textarea/Textarea.js +1 -1
- package/dist/components/textarea/Textarea.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/resolveZoraNavigationItems.d.ts +2 -2
- package/dist/internal/resolveZoraNavigationItems.d.ts.map +1 -1
- package/dist/internal/resolveZoraNavigationItems.js +4 -3
- package/dist/internal/resolveZoraNavigationItems.js.map +1 -1
- package/dist/layout/app-shell/AppShell.d.ts.map +1 -1
- package/dist/layout/app-shell/AppShell.js +2 -4
- package/dist/layout/app-shell/AppShell.js.map +1 -1
- package/dist/patterns/auth/oauthProviders.d.ts +9 -0
- package/dist/patterns/auth/oauthProviders.d.ts.map +1 -1
- package/dist/patterns/auth/oauthProviders.js +9 -9
- package/dist/patterns/auth/oauthProviders.js.map +1 -1
- package/dist/patterns/auth/types.d.ts +2 -6
- package/dist/patterns/auth/types.d.ts.map +1 -1
- package/dist/patterns/auth/types.js.map +1 -1
- package/dist/patterns/scanner/BarcodeScannerView.js +1 -1
- package/dist/patterns/scanner/BarcodeScannerView.js.map +1 -1
- package/dist/patterns/timeline/Timeline.d.ts.map +1 -1
- package/dist/patterns/timeline/Timeline.js +1 -1
- package/dist/patterns/timeline/Timeline.js.map +1 -1
- package/dist/patterns/zora-tab-bar/ZoraTabBar.d.ts.map +1 -1
- package/dist/patterns/zora-tab-bar/ZoraTabBar.js +1 -1
- package/dist/patterns/zora-tab-bar/ZoraTabBar.js.map +1 -1
- package/package.json +34 -29
- package/src/components/action-sheet/ActionSheetItem.tsx +1 -6
- package/src/components/app-bar/AppBar.tsx +3 -3
- package/src/components/avatar/Avatar.tsx +1 -8
- package/src/components/breadcrumbs/Breadcrumbs.tsx +1 -2
- package/src/components/chip/Chip.tsx +1 -8
- package/src/components/gradient/Gradient.tsx +16 -12
- package/src/components/gradient/GradientRendererContext.tsx +27 -0
- package/src/components/gradient/index.ts +4 -0
- package/src/components/gradient/types.ts +17 -0
- package/src/components/icon/Icon.tsx +1 -1
- package/src/components/input/Input.tsx +2 -12
- package/src/components/menu/Menu.tsx +1 -8
- package/src/components/metric-card/MetricCard.tsx +1 -8
- package/src/components/select/Select.tsx +1 -1
- package/src/components/textarea/Textarea.tsx +2 -12
- package/src/expo57Migration.test.ts +125 -0
- package/src/index.ts +4 -1
- package/src/interactionPolicy.test.ts +1 -1
- package/src/internal/resolveZoraNavigationItems.test.ts +11 -0
- package/src/internal/resolveZoraNavigationItems.ts +7 -6
- package/src/layout/app-shell/AppShell.tsx +2 -6
- package/src/metadata/componentMeta.test.ts +2 -1
- package/src/nativePeerContract.test.ts +5 -3
- package/src/patterns/auth/oauthProviders.test.ts +25 -0
- package/src/patterns/auth/oauthProviders.ts +9 -9
- package/src/patterns/auth/types.ts +2 -6
- package/src/patterns/scanner/BarcodeScannerView.tsx +1 -1
- package/src/patterns/timeline/Timeline.tsx +1 -2
- package/src/patterns/zora-tab-bar/ZoraTabBar.tsx +1 -2
- package/src/platformAcceptance.test.ts +14 -0
- package/src/registry.test.ts +5 -1
- package/src/theme/themeScopeStructure.test.ts +1 -1
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { describe, expect, test } from 'bun:test';
|
|
5
|
+
|
|
6
|
+
const ROOT = process.cwd();
|
|
7
|
+
const EXPO_EXAMPLE_DIRS = [
|
|
8
|
+
'examples/expo-showcase',
|
|
9
|
+
'examples/food_drink/restaurant',
|
|
10
|
+
'examples/shopping_commerce/marketplace',
|
|
11
|
+
'examples/shopping_commerce/storefront',
|
|
12
|
+
'examples/social_community/community-feed',
|
|
13
|
+
'examples/social_community/photo-social',
|
|
14
|
+
'examples/social_community/private-messaging',
|
|
15
|
+
'examples/social_community/visual-discovery',
|
|
16
|
+
] as const;
|
|
17
|
+
const RNVI_PLUGINS = [
|
|
18
|
+
'@react-native-vector-icons/fontawesome',
|
|
19
|
+
'@react-native-vector-icons/fontawesome5',
|
|
20
|
+
'@react-native-vector-icons/fontawesome6',
|
|
21
|
+
'@react-native-vector-icons/ionicons',
|
|
22
|
+
] as const;
|
|
23
|
+
|
|
24
|
+
function readJson(path: string): Record<string, unknown> {
|
|
25
|
+
const value: unknown = JSON.parse(readFileSync(path, 'utf8'));
|
|
26
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
27
|
+
throw new Error(`Expected an object in ${path}.`);
|
|
28
|
+
}
|
|
29
|
+
return value as Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function readRecord(record: Record<string, unknown>, key: string): Record<string, unknown> {
|
|
33
|
+
const value = Reflect.get(record, key);
|
|
34
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
35
|
+
throw new Error(`Expected ${key} to be an object.`);
|
|
36
|
+
}
|
|
37
|
+
return value as Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readValue(record: Record<string, unknown>, key: string): unknown {
|
|
41
|
+
return Reflect.get(record, key);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function readExamplePackage(directory: string): Record<string, unknown> {
|
|
45
|
+
return readJson(join(ROOT, directory, 'package.json'));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
describe('portable ZORA package boundary', () => {
|
|
49
|
+
test('targets the released RN 0.86 and Surface 3 contract without Expo runtime peers', () => {
|
|
50
|
+
const packageJson = readJson(join(ROOT, 'package.json'));
|
|
51
|
+
const dependencies = readRecord(packageJson, 'dependencies');
|
|
52
|
+
const peers = readRecord(packageJson, 'peerDependencies');
|
|
53
|
+
const development = readRecord(packageJson, 'devDependencies');
|
|
54
|
+
|
|
55
|
+
expect(readValue(dependencies, '@ankhorage/surface')).toBe('^3.0.0');
|
|
56
|
+
expect(readValue(dependencies, '@ankhorage/contracts')).toBe('^8.0.0');
|
|
57
|
+
expect(peers.react).toBe('19.2.3');
|
|
58
|
+
expect(readValue(peers, 'react-native')).toBe('0.86.2');
|
|
59
|
+
expect(readValue(peers, 'react-native-web')).toBe('~0.21.0');
|
|
60
|
+
expect(development.typescript).toBe('~6.0.3');
|
|
61
|
+
|
|
62
|
+
for (const expoPackage of ['@expo/vector-icons', 'expo-font', 'expo-linear-gradient']) {
|
|
63
|
+
expect(readValue(peers, expoPackage)).toBeUndefined();
|
|
64
|
+
expect(readValue(development, expoPackage)).toBeUndefined();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('contains no Expo runtime import or removed RN 0.85 style API', () => {
|
|
69
|
+
const runtimeSource = readFileSync(
|
|
70
|
+
join(ROOT, 'src', 'components', 'gradient', 'Gradient.tsx'),
|
|
71
|
+
'utf8',
|
|
72
|
+
);
|
|
73
|
+
const shellSource = readFileSync(
|
|
74
|
+
join(ROOT, 'src', 'layout', 'app-shell', 'AppShell.tsx'),
|
|
75
|
+
'utf8',
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
expect(runtimeSource).not.toContain("from 'expo");
|
|
79
|
+
expect(shellSource).not.toContain('absoluteFillObject');
|
|
80
|
+
expect(shellSource).not.toMatch(/pointerEvents=/);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('Expo 57 example boundary', () => {
|
|
85
|
+
test('uses the canonical React, RN, RNW, TypeScript, and Expo baselines', () => {
|
|
86
|
+
for (const directory of EXPO_EXAMPLE_DIRS) {
|
|
87
|
+
const packageJson = readExamplePackage(directory);
|
|
88
|
+
const dependencies = readRecord(packageJson, 'dependencies');
|
|
89
|
+
const development = readRecord(packageJson, 'devDependencies');
|
|
90
|
+
|
|
91
|
+
expect(dependencies.expo).toBe('~57.0.15');
|
|
92
|
+
expect(dependencies.react).toBe('19.2.3');
|
|
93
|
+
expect(readValue(dependencies, 'react-native')).toBe('0.86.2');
|
|
94
|
+
expect(readValue(dependencies, 'react-native-web')).toBe('~0.21.0');
|
|
95
|
+
expect(development.typescript).toBe('~6.0.3');
|
|
96
|
+
expect(readValue(dependencies, '@expo/vector-icons')).toBeUndefined();
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('registers all scoped RNVI packages in each Expo app config', () => {
|
|
101
|
+
for (const directory of EXPO_EXAMPLE_DIRS) {
|
|
102
|
+
const appJson = readJson(join(ROOT, directory, 'app.json'));
|
|
103
|
+
const expo = readRecord(appJson, 'expo');
|
|
104
|
+
const { plugins } = expo;
|
|
105
|
+
expect(Array.isArray(plugins)).toBe(true);
|
|
106
|
+
|
|
107
|
+
for (const plugin of RNVI_PLUGINS) {
|
|
108
|
+
expect(plugins).toContain(plugin);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('loads every icon font face exercised by Web acceptance', () => {
|
|
114
|
+
const webFontSource = readFileSync(
|
|
115
|
+
join(ROOT, 'examples', 'expo-showcase', 'useZoraIconFonts.web.ts'),
|
|
116
|
+
'utf8',
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
expect(webFontSource).toContain('Ionicons.ttf');
|
|
120
|
+
expect(webFontSource).toContain('FontAwesome.ttf');
|
|
121
|
+
expect(webFontSource).toContain('FontAwesome5_Brands.ttf');
|
|
122
|
+
expect(webFontSource).toContain('FontAwesome5_Solid.ttf');
|
|
123
|
+
expect(webFontSource).toContain('FontAwesome6_Brands.ttf');
|
|
124
|
+
});
|
|
125
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -74,8 +74,11 @@ export type {
|
|
|
74
74
|
GradientLocations,
|
|
75
75
|
GradientPoint,
|
|
76
76
|
GradientProps,
|
|
77
|
+
GradientRenderer,
|
|
78
|
+
GradientRendererProps,
|
|
79
|
+
GradientRendererProviderProps,
|
|
77
80
|
} from './components/gradient';
|
|
78
|
-
export { Gradient } from './components/gradient';
|
|
81
|
+
export { Gradient, GradientRendererProvider } from './components/gradient';
|
|
79
82
|
export type {
|
|
80
83
|
HeadingAlign,
|
|
81
84
|
HeadingColor,
|
|
@@ -203,7 +203,7 @@ describe('Select', () => {
|
|
|
203
203
|
test('prevents pointer/touch interaction with Picker subtree while passive', () => {
|
|
204
204
|
const source = readComponent('select', 'Select.tsx');
|
|
205
205
|
|
|
206
|
-
expect(source).toMatch(/pointerEvents
|
|
206
|
+
expect(source).toMatch(/pointerEvents:\s*passive \? 'none' : 'auto'/);
|
|
207
207
|
expect(source).toMatch(
|
|
208
208
|
/onValueChange=\{\s*\(\s*itemValue\s*\)\s*=>\s*\{\s*if\s*\(\s*!passive\s*\)/,
|
|
209
209
|
);
|
|
@@ -60,6 +60,17 @@ describe('resolveRouteLabel', () => {
|
|
|
60
60
|
|
|
61
61
|
expect(result).toEqual({ label: 'profile', source: 'name' });
|
|
62
62
|
});
|
|
63
|
+
|
|
64
|
+
test('uses descriptor title instead of invoking a callable Expo tab label', () => {
|
|
65
|
+
const result = resolveRouteLabel({
|
|
66
|
+
route: { key: 'k4', name: 'home' },
|
|
67
|
+
metadata: undefined,
|
|
68
|
+
descriptor: { options: { tabBarLabel: () => 'callable', title: 'Home title' } },
|
|
69
|
+
kind: 'tab',
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(result).toEqual({ label: 'Home title', source: 'descriptor' });
|
|
73
|
+
});
|
|
63
74
|
});
|
|
64
75
|
|
|
65
76
|
describe('resolveNavigationItems', () => {
|
|
@@ -8,8 +8,8 @@ import type { ZoraNavigationRouteMap } from '../components/navigation-list';
|
|
|
8
8
|
|
|
9
9
|
interface ZoraNavigationDescriptorOptions {
|
|
10
10
|
title?: string;
|
|
11
|
-
tabBarLabel?:
|
|
12
|
-
drawerLabel?:
|
|
11
|
+
tabBarLabel?: unknown;
|
|
12
|
+
drawerLabel?: unknown;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export interface ZoraNavigationDescriptor {
|
|
@@ -71,13 +71,14 @@ export function resolveRouteLabel({
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
const options = descriptor?.options;
|
|
74
|
+
const configuredLabel = kind === 'tab' ? options?.tabBarLabel : options?.drawerLabel;
|
|
74
75
|
const fallback =
|
|
75
|
-
|
|
76
|
-
?
|
|
77
|
-
:
|
|
76
|
+
configuredLabel === undefined || typeof configuredLabel === 'function'
|
|
77
|
+
? options?.title
|
|
78
|
+
: configuredLabel;
|
|
78
79
|
|
|
79
80
|
if (fallback !== undefined) {
|
|
80
|
-
return { label: fallback, source: 'descriptor' };
|
|
81
|
+
return { label: fallback as React.ReactNode, source: 'descriptor' };
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
return { label: route.name, source: 'name' };
|
|
@@ -24,11 +24,7 @@ function AppShellInner({
|
|
|
24
24
|
|
|
25
25
|
{footer ? <View style={styles.slot}>{footer}</View> : null}
|
|
26
26
|
|
|
27
|
-
{overlay ?
|
|
28
|
-
<View pointerEvents="box-none" style={styles.overlay}>
|
|
29
|
-
{overlay}
|
|
30
|
-
</View>
|
|
31
|
-
) : null}
|
|
27
|
+
{overlay ? <View style={[StyleSheet.absoluteFill, styles.overlay]}>{overlay}</View> : null}
|
|
32
28
|
</View>
|
|
33
29
|
</Box>
|
|
34
30
|
);
|
|
@@ -63,7 +59,7 @@ const styles = StyleSheet.create({
|
|
|
63
59
|
flexShrink: 0,
|
|
64
60
|
},
|
|
65
61
|
overlay: {
|
|
66
|
-
|
|
62
|
+
pointerEvents: 'box-none',
|
|
67
63
|
zIndex: 10,
|
|
68
64
|
},
|
|
69
65
|
});
|
|
@@ -27,7 +27,7 @@ describe('ZORA_COMPONENT_META registry coverage', () => {
|
|
|
27
27
|
.flatMap((match) => match[1].split(',').map((item) => item.trim()))
|
|
28
28
|
.map((item) => item.split(' as ')[0].trim())
|
|
29
29
|
.filter((name) => /^[A-Z][A-Za-z0-9]+$/.test(name))
|
|
30
|
-
.filter((name) => !['ToastProvider'].includes(name));
|
|
30
|
+
.filter((name) => !['GradientRendererProvider', 'ToastProvider'].includes(name));
|
|
31
31
|
componentExports.push('ThemeModeToggle');
|
|
32
32
|
|
|
33
33
|
for (const name of componentExports) {
|
|
@@ -40,6 +40,7 @@ describe('ZORA_COMPONENT_META registry coverage', () => {
|
|
|
40
40
|
|
|
41
41
|
test('does not treat providers/scopes as direct manifest UI nodes', () => {
|
|
42
42
|
expect(ZORA_COMPONENT_META.ToastProvider?.directManifestNode).toBe(false);
|
|
43
|
+
expect(ZORA_COMPONENT_META.GradientRendererProvider).toBeUndefined();
|
|
43
44
|
expect(ZORA_COMPONENT_META.ZoraProvider).toBeUndefined();
|
|
44
45
|
});
|
|
45
46
|
});
|
|
@@ -22,13 +22,15 @@ function isOptionalPeer(metadata: unknown, packageName: string): boolean {
|
|
|
22
22
|
return isRecord(peerMetadata) && peerMetadata.optional === true;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
test('root-entry native imports are required peers', async () => {
|
|
25
|
+
test('root-entry native imports are required portable peers', async () => {
|
|
26
26
|
const packageJson = JSON.parse(
|
|
27
27
|
await readFile(new URL('../package.json', import.meta.url), 'utf8'),
|
|
28
28
|
) as unknown;
|
|
29
29
|
if (!isRecord(packageJson)) throw new Error('Expected package.json to contain an object.');
|
|
30
30
|
|
|
31
|
-
const { peerDependenciesMeta } = packageJson;
|
|
32
|
-
expect(isOptionalPeer(peerDependenciesMeta, 'expo-linear-gradient')).toBe(false);
|
|
31
|
+
const { peerDependencies, peerDependenciesMeta } = packageJson;
|
|
33
32
|
expect(isOptionalPeer(peerDependenciesMeta, '@react-native-picker/picker')).toBe(false);
|
|
33
|
+
expect(isRecord(peerDependencies) && peerDependencies['expo-linear-gradient']).toBeUndefined();
|
|
34
|
+
expect(isRecord(peerDependencies) && peerDependencies['expo-font']).toBeUndefined();
|
|
35
|
+
expect(isRecord(peerDependencies) && peerDependencies['@expo/vector-icons']).toBeUndefined();
|
|
34
36
|
});
|
|
@@ -23,6 +23,31 @@ describe('OAuth provider UI helpers', () => {
|
|
|
23
23
|
expect(resolveOAuthProviderIcon('google')).toEqual({ provider: 'FontAwesome', name: 'google' });
|
|
24
24
|
expect(resolveOAuthProviderIcon('github')).toEqual({ provider: 'FontAwesome', name: 'github' });
|
|
25
25
|
expect(DEFAULT_OAUTH_PROVIDER_ICONS.apple).toEqual({ provider: 'FontAwesome', name: 'apple' });
|
|
26
|
+
expect(DEFAULT_OAUTH_PROVIDER_ICONS.microsoft).toEqual({
|
|
27
|
+
provider: 'FontAwesome5',
|
|
28
|
+
name: 'microsoft',
|
|
29
|
+
variant: 'brand',
|
|
30
|
+
});
|
|
31
|
+
expect(DEFAULT_OAUTH_PROVIDER_ICONS.discord).toEqual({
|
|
32
|
+
provider: 'FontAwesome5',
|
|
33
|
+
name: 'discord',
|
|
34
|
+
variant: 'brand',
|
|
35
|
+
});
|
|
36
|
+
expect(DEFAULT_OAUTH_PROVIDER_ICONS.gitlab).toEqual({
|
|
37
|
+
provider: 'FontAwesome5',
|
|
38
|
+
name: 'gitlab',
|
|
39
|
+
variant: 'brand',
|
|
40
|
+
});
|
|
41
|
+
expect(DEFAULT_OAUTH_PROVIDER_ICONS.zoom).toEqual({
|
|
42
|
+
provider: 'FontAwesome5',
|
|
43
|
+
name: 'video',
|
|
44
|
+
variant: 'solid',
|
|
45
|
+
});
|
|
46
|
+
expect(DEFAULT_OAUTH_PROVIDER_ICONS.x).toEqual({
|
|
47
|
+
provider: 'FontAwesome6',
|
|
48
|
+
name: 'x-twitter',
|
|
49
|
+
variant: 'brand',
|
|
50
|
+
});
|
|
26
51
|
});
|
|
27
52
|
|
|
28
53
|
it('returns undefined for custom provider icons', () => {
|
|
@@ -2,22 +2,22 @@ import type { OAuthProviderIconSpec } from './types';
|
|
|
2
2
|
|
|
3
3
|
export const DEFAULT_OAUTH_PROVIDER_ICONS = {
|
|
4
4
|
apple: { provider: 'FontAwesome', name: 'apple' },
|
|
5
|
-
azure: { provider: 'FontAwesome5', name: 'microsoft' },
|
|
5
|
+
azure: { provider: 'FontAwesome5', name: 'microsoft', variant: 'brand' },
|
|
6
6
|
bitbucket: { provider: 'FontAwesome', name: 'bitbucket' },
|
|
7
|
-
discord: { provider: 'FontAwesome5', name: 'discord' },
|
|
7
|
+
discord: { provider: 'FontAwesome5', name: 'discord', variant: 'brand' },
|
|
8
8
|
facebook: { provider: 'FontAwesome', name: 'facebook' },
|
|
9
|
-
figma: { provider: 'FontAwesome5', name: 'figma' },
|
|
9
|
+
figma: { provider: 'FontAwesome5', name: 'figma', variant: 'brand' },
|
|
10
10
|
github: { provider: 'FontAwesome', name: 'github' },
|
|
11
|
-
gitlab: { provider: 'FontAwesome5', name: 'gitlab' },
|
|
11
|
+
gitlab: { provider: 'FontAwesome5', name: 'gitlab', variant: 'brand' },
|
|
12
12
|
google: { provider: 'FontAwesome', name: 'google' },
|
|
13
13
|
linkedin: { provider: 'FontAwesome', name: 'linkedin' },
|
|
14
|
-
microsoft: { provider: 'FontAwesome5', name: 'microsoft' },
|
|
15
|
-
slack: { provider: 'FontAwesome5', name: 'slack' },
|
|
14
|
+
microsoft: { provider: 'FontAwesome5', name: 'microsoft', variant: 'brand' },
|
|
15
|
+
slack: { provider: 'FontAwesome5', name: 'slack', variant: 'brand' },
|
|
16
16
|
spotify: { provider: 'FontAwesome', name: 'spotify' },
|
|
17
|
-
twitch: { provider: 'FontAwesome5', name: 'twitch' },
|
|
17
|
+
twitch: { provider: 'FontAwesome5', name: 'twitch', variant: 'brand' },
|
|
18
18
|
twitter: { provider: 'FontAwesome', name: 'twitter' },
|
|
19
|
-
x: { provider: 'FontAwesome6', name: 'x-twitter' },
|
|
20
|
-
zoom: { provider: 'FontAwesome5', name: 'video' },
|
|
19
|
+
x: { provider: 'FontAwesome6', name: 'x-twitter', variant: 'brand' },
|
|
20
|
+
zoom: { provider: 'FontAwesome5', name: 'video', variant: 'solid' },
|
|
21
21
|
} as const satisfies Record<string, OAuthProviderIconSpec>;
|
|
22
22
|
|
|
23
23
|
const DEFAULT_OAUTH_PROVIDER_LABELS = {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ButtonIconSpec } from '@ankhorage/surface';
|
|
1
2
|
import type React from 'react';
|
|
2
3
|
|
|
3
4
|
import type { ButtonProps } from '../../components/button';
|
|
@@ -67,12 +68,7 @@ export interface OtpFormProps extends AuthFormBaseProps {
|
|
|
67
68
|
onResend?: () => void | Promise<void>;
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
export
|
|
71
|
-
name: string;
|
|
72
|
-
provider?: string;
|
|
73
|
-
size?: number | string;
|
|
74
|
-
color?: string;
|
|
75
|
-
}
|
|
71
|
+
export type OAuthProviderIconSpec = ButtonIconSpec;
|
|
76
72
|
|
|
77
73
|
export interface OAuthProviderItem {
|
|
78
74
|
id: string;
|
|
@@ -70,7 +70,7 @@ function BarcodeScannerViewInner({
|
|
|
70
70
|
) : (
|
|
71
71
|
<View style={[styles.placeholder, placeholderStyle]} />
|
|
72
72
|
)}
|
|
73
|
-
<View
|
|
73
|
+
<View style={[styles.overlay, { pointerEvents: 'none' }]}>
|
|
74
74
|
<ScanOverlay
|
|
75
75
|
cornerLabel={cornerLabel}
|
|
76
76
|
description={overlayDescription}
|
|
@@ -110,9 +110,8 @@ function ZoraTabBarInner({
|
|
|
110
110
|
>
|
|
111
111
|
{item.metadata?.icon ? (
|
|
112
112
|
<Icon
|
|
113
|
+
{...item.metadata.icon}
|
|
113
114
|
color={contentColor}
|
|
114
|
-
name={item.metadata.icon.name}
|
|
115
|
-
provider={item.metadata.icon.provider}
|
|
116
115
|
size={compact ? theme.spacing.m : theme.spacing.l}
|
|
117
116
|
/>
|
|
118
117
|
) : null}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
test('passes the isolated Surface 3 and RN Web 0.21 acceptance suite', () => {
|
|
4
|
+
const subprocess = Bun.spawnSync({
|
|
5
|
+
cmd: [process.execPath, 'test', 'test-fixtures/platformAcceptance.test.tsx'],
|
|
6
|
+
stderr: 'pipe',
|
|
7
|
+
stdout: 'pipe',
|
|
8
|
+
});
|
|
9
|
+
const output = `${subprocess.stdout.toString()}\n${subprocess.stderr.toString()}`;
|
|
10
|
+
|
|
11
|
+
expect(subprocess.exitCode, output).toBe(0);
|
|
12
|
+
expect(output).toContain('4 pass');
|
|
13
|
+
expect(output).toContain('0 fail');
|
|
14
|
+
});
|
package/src/registry.test.ts
CHANGED
|
@@ -2,7 +2,11 @@ import { describe, expect, test } from 'bun:test';
|
|
|
2
2
|
|
|
3
3
|
import type { ZoraComponentRegistry } from './index';
|
|
4
4
|
|
|
5
|
-
const NON_RUNTIME_COMPONENT_EXPORTS = new Set([
|
|
5
|
+
const NON_RUNTIME_COMPONENT_EXPORTS = new Set([
|
|
6
|
+
'GradientRendererProvider',
|
|
7
|
+
'SelectionProvider',
|
|
8
|
+
'ToastProvider',
|
|
9
|
+
]);
|
|
6
10
|
const RUNTIME_THEME_COMPONENT_EXPORTS = ['ThemeModeToggle'] as const;
|
|
7
11
|
const REGISTRY_SNAPSHOT_PREFIX = 'ZORA_REGISTRY_SNAPSHOT:';
|
|
8
12
|
|
|
@@ -210,7 +210,7 @@ describe('theme scope structure', () => {
|
|
|
210
210
|
for (const filePath of scopedPropTypeFiles) {
|
|
211
211
|
const source = readFileSync(filePath, 'utf8');
|
|
212
212
|
expect(source).toMatch(/ZoraBaseProps/);
|
|
213
|
-
expect(source).toMatch(/extends\s+ZoraBaseProps/);
|
|
213
|
+
expect(source).toMatch(/extends\s+ZoraBaseProps|ZoraBaseProps\s*&|&\s*ZoraBaseProps/);
|
|
214
214
|
}
|
|
215
215
|
});
|
|
216
216
|
|