@ankhorage/zora 23.0.0 → 23.2.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.
Files changed (203) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1 -1
  3. package/dist/constants/authoring.d.ts +4 -4
  4. package/dist/constants/authoring.d.ts.map +1 -1
  5. package/dist/constants/authoring.js +2 -0
  6. package/dist/constants/authoring.js.map +1 -1
  7. package/dist/features/accordion/accordionItemMeta.d.ts +1 -1
  8. package/dist/features/auth/adapters/inbound/AuthScreen.d.ts +10 -0
  9. package/dist/features/auth/adapters/inbound/AuthScreen.d.ts.map +1 -0
  10. package/dist/features/auth/adapters/inbound/AuthScreen.js +67 -0
  11. package/dist/features/auth/adapters/inbound/AuthScreen.js.map +1 -0
  12. package/dist/features/auth/authScreenMeta.d.ts +204 -0
  13. package/dist/features/auth/authScreenMeta.d.ts.map +1 -0
  14. package/dist/features/auth/authScreenMeta.js +112 -0
  15. package/dist/features/auth/authScreenMeta.js.map +1 -0
  16. package/dist/features/auth/public.d.ts +2 -1
  17. package/dist/features/auth/public.d.ts.map +1 -1
  18. package/dist/features/auth/public.js +1 -0
  19. package/dist/features/auth/public.js.map +1 -1
  20. package/dist/features/bottom-sheet/bottomSheetMeta.d.ts +1 -1
  21. package/dist/features/card/cardMeta.d.ts +1 -1
  22. package/dist/features/card/mediaCardMeta.d.ts +1 -1
  23. package/dist/features/card/postCardMeta.d.ts +1 -1
  24. package/dist/features/chat/messageBubbleMeta.d.ts +1 -1
  25. package/dist/features/dialog/dialogMeta.d.ts +2 -2
  26. package/dist/features/gradient/gradientMeta.d.ts +1 -1
  27. package/dist/features/keyboard-avoiding-view/keyboardAvoidingViewMeta.d.ts +1 -1
  28. package/dist/features/layout/gridMeta.d.ts +1 -1
  29. package/dist/features/layout/screenMeta.d.ts +1 -1
  30. package/dist/features/layout/scrollViewMeta.d.ts +1 -1
  31. package/dist/features/layout/viewMeta.d.ts +1 -1
  32. package/dist/features/list/flatListMeta.d.ts +1 -1
  33. package/dist/features/list/sectionListMeta.d.ts +1 -1
  34. package/dist/features/reader/meta.d.ts +2 -2
  35. package/dist/features/registry/ZORA_COMPONENT_REGISTRY.d.ts.map +1 -1
  36. package/dist/features/registry/ZORA_COMPONENT_REGISTRY.js +2 -1
  37. package/dist/features/registry/ZORA_COMPONENT_REGISTRY.js.map +1 -1
  38. package/dist/features/registry/bindableComponentMeta.d.ts +2 -2
  39. package/dist/features/registry/componentMeta.d.ts.map +1 -1
  40. package/dist/features/registry/componentMeta.js +2 -0
  41. package/dist/features/registry/componentMeta.js.map +1 -1
  42. package/dist/features/scanner/meta.d.ts +2 -2
  43. package/dist/features/section/screenSectionMeta.d.ts +1 -1
  44. package/dist/features/surface/surfaceMeta.d.ts +1 -1
  45. package/dist/features/tabs/tabPanelMeta.d.ts +1 -1
  46. package/dist/features/tree-view/adapters/inbound/TreeItem.d.ts.map +1 -1
  47. package/dist/features/tree-view/adapters/inbound/TreeItem.js +2 -1
  48. package/dist/features/tree-view/adapters/inbound/TreeItem.js.map +1 -1
  49. package/dist/features/tree-view/adapters/inbound/web-artifact/TreeItemRow.d.ts.map +1 -1
  50. package/dist/features/tree-view/adapters/inbound/web-artifact/TreeItemRow.js +5 -4
  51. package/dist/features/tree-view/adapters/inbound/web-artifact/TreeItemRow.js.map +1 -1
  52. package/dist/features/tree-view/adapters/inbound/web-artifact/TreeView.d.ts +1 -0
  53. package/dist/features/tree-view/adapters/inbound/web-artifact/TreeView.d.ts.map +1 -1
  54. package/dist/features/tree-view/adapters/inbound/web-artifact/TreeView.js.map +1 -1
  55. package/dist/index.d.ts +2 -2
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +1 -1
  58. package/dist/index.js.map +1 -1
  59. package/dist/types/auth.d.ts +19 -0
  60. package/dist/types/auth.d.ts.map +1 -1
  61. package/dist/types/auth.js.map +1 -1
  62. package/dist/types/tree-view.d.ts +1 -0
  63. package/dist/types/tree-view.d.ts.map +1 -1
  64. package/dist/types/tree-view.js.map +1 -1
  65. package/package.json +2 -2
  66. package/src/constants/authoring.ts +2 -0
  67. package/src/features/auth/adapters/inbound/AuthScreen.tsx +202 -0
  68. package/src/features/auth/authScreenMeta.ts +114 -0
  69. package/src/features/auth/public.test.ts +6 -0
  70. package/src/features/auth/public.ts +3 -0
  71. package/src/features/registry/ZORA_COMPONENT_REGISTRY.ts +2 -0
  72. package/src/features/registry/componentMeta.test.ts +1 -0
  73. package/src/features/registry/componentMeta.ts +2 -0
  74. package/src/features/tree-view/adapters/inbound/TreeItem.tsx +3 -2
  75. package/src/features/tree-view/adapters/inbound/web-artifact/TreeItemRow.tsx +12 -3
  76. package/src/features/tree-view/adapters/inbound/web-artifact/TreeView.test.tsx +19 -0
  77. package/src/features/tree-view/adapters/inbound/web-artifact/TreeView.tsx +1 -0
  78. package/src/index.ts +3 -0
  79. package/src/showcaseCoverage.test.ts +1 -0
  80. package/src/types/auth.ts +21 -0
  81. package/src/types/tree-view.ts +1 -0
  82. package/web-dist/chunks/{Accordion-q165k3az.js → Accordion-2ak69ntj.js} +9 -9
  83. package/web-dist/chunks/{Accordion-rx2gzadh.js → Accordion-46vwm9xv.js} +2 -2
  84. package/web-dist/chunks/{Accordion-xf8cj8z4.js → Accordion-4r9a9qny.js} +3 -3
  85. package/web-dist/chunks/{Accordion-w0k7gnn9.js → Accordion-5pskbqss.js} +5 -5
  86. package/web-dist/chunks/{Accordion-09se459d.js → Accordion-8xdet564.js} +13 -13
  87. package/web-dist/chunks/{Accordion-czmnsspb.js → Accordion-9n7h9hag.js} +6 -6
  88. package/web-dist/chunks/{Accordion-x1dg1f47.js → Accordion-b9myvfep.js} +3 -3
  89. package/web-dist/chunks/{Accordion-rspy7gjb.js → Accordion-bmp1ab7m.js} +494 -301
  90. package/web-dist/chunks/{Accordion-x13vca75.js → Accordion-cqgbx1pw.js} +3 -3
  91. package/web-dist/chunks/{Accordion-e633pb7z.js → Accordion-cydzrpk2.js} +1 -1
  92. package/web-dist/chunks/{Accordion-89q14src.js → Accordion-ejns5mga.js} +4 -4
  93. package/web-dist/chunks/{Accordion-f1t3rzgg.js → Accordion-ejy7gr0a.js} +4 -4
  94. package/web-dist/chunks/{Accordion-83hfn3y4.js → Accordion-f2mfgcx6.js} +13 -13
  95. package/web-dist/chunks/{Accordion-bsy1jrak.js → Accordion-ff583p4q.js} +2 -2
  96. package/web-dist/chunks/{Accordion-k7wwyx5x.js → Accordion-jksn8783.js} +3 -3
  97. package/web-dist/chunks/{Accordion-w7jv9y5t.js → Accordion-jnwa02s7.js} +2 -2
  98. package/web-dist/chunks/{Accordion-gkzhd3zk.js → Accordion-kmv2fp6m.js} +4 -4
  99. package/web-dist/chunks/{Accordion-cn8tbdvk.js → Accordion-mm4kx13n.js} +8 -8
  100. package/web-dist/chunks/{Accordion-b3ymabze.js → Accordion-nggjwm07.js} +3 -3
  101. package/web-dist/chunks/{Accordion-zx0jc0kg.js → Accordion-qb8ppq9t.js} +5 -5
  102. package/web-dist/chunks/Accordion-r23sx4gf.js +34 -0
  103. package/web-dist/chunks/{Accordion-q3z741vt.js → Accordion-rev0zb75.js} +4 -4
  104. package/web-dist/chunks/{Accordion-w1afjp87.js → Accordion-rnjt5z4y.js} +17 -17
  105. package/web-dist/chunks/{Accordion-swys7qts.js → Accordion-tyqds4zr.js} +4 -4
  106. package/web-dist/chunks/{Accordion-xzd0tx46.js → Accordion-v166qr59.js} +3 -3
  107. package/web-dist/chunks/{Accordion-gj63vb6b.js → Accordion-xw1gkpfk.js} +3 -3
  108. package/web-dist/chunks/{Accordion-dp638q63.js → Accordion-yms7x22j.js} +7 -7
  109. package/web-dist/chunks/{Accordion-fm3jxs1f.js → Accordion-z1trs7s1.js} +22 -22
  110. package/web-dist/chunks/{Accordion-5qmfa7vr.js → Accordion-z8h1hn96.js} +5 -5
  111. package/web-dist/components/accordion/Accordion.js +2 -2
  112. package/web-dist/components/accordion-item/AccordionItem.js +2 -2
  113. package/web-dist/components/app-bar/AppBar.js +6 -6
  114. package/web-dist/components/auth-screen/AuthScreen.d.ts +9 -0
  115. package/web-dist/components/auth-screen/AuthScreen.js +43 -0
  116. package/web-dist/components/auth-screen/index.d.ts +1 -0
  117. package/web-dist/components/auth-screen/index.js +2 -0
  118. package/web-dist/components/avatar/Avatar.js +2 -2
  119. package/web-dist/components/avatar-group/AvatarGroup.js +2 -2
  120. package/web-dist/components/badge/Badge.js +2 -2
  121. package/web-dist/components/barcode-scanner-view/BarcodeScannerView.js +8 -8
  122. package/web-dist/components/breadcrumbs/Breadcrumbs.js +8 -8
  123. package/web-dist/components/button/Button.js +3 -3
  124. package/web-dist/components/button-group/ButtonGroup.js +3 -3
  125. package/web-dist/components/camera-permission-view/CameraPermissionView.js +8 -8
  126. package/web-dist/components/card/Card.js +7 -7
  127. package/web-dist/components/chat-list-item/ChatListItem.js +6 -6
  128. package/web-dist/components/checkbox/Checkbox.js +4 -4
  129. package/web-dist/components/checkbox-group/CheckboxGroup.js +4 -4
  130. package/web-dist/components/chip/Chip.js +2 -2
  131. package/web-dist/components/chip-group/ChipGroup.js +2 -2
  132. package/web-dist/components/collection-editor/CollectionEditor.js +9 -9
  133. package/web-dist/components/content-rail/ContentRail.js +6 -6
  134. package/web-dist/components/data-table/DataTable.js +18 -18
  135. package/web-dist/components/date-picker/DatePicker.js +12 -12
  136. package/web-dist/components/dialog/Dialog.js +3 -3
  137. package/web-dist/components/empty-state/EmptyState.js +8 -8
  138. package/web-dist/components/field/Field.js +5 -5
  139. package/web-dist/components/flat-list/FlatList.js +5 -5
  140. package/web-dist/components/forgot-password-form/ForgotPasswordForm.d.ts +1 -0
  141. package/web-dist/components/forgot-password-form/ForgotPasswordForm.js +21 -16
  142. package/web-dist/components/form/Form.js +7 -7
  143. package/web-dist/components/form-actions/FormActions.js +7 -7
  144. package/web-dist/components/form-error/FormError.js +7 -7
  145. package/web-dist/components/heading/Heading.js +3 -3
  146. package/web-dist/components/hero/Hero.js +10 -10
  147. package/web-dist/components/icon-button/IconButton.js +3 -3
  148. package/web-dist/components/keyboard-avoiding-view/KeyboardAvoidingView.js +5 -32
  149. package/web-dist/components/list/List.js +5 -5
  150. package/web-dist/components/list-item/ListItem.js +5 -5
  151. package/web-dist/components/list-section/ListSection.js +5 -5
  152. package/web-dist/components/media-card/MediaCard.js +7 -7
  153. package/web-dist/components/message-bubble/MessageBubble.js +6 -6
  154. package/web-dist/components/metric-card/MetricCard.js +7 -7
  155. package/web-dist/components/missing-element/MissingElement.js +8 -8
  156. package/web-dist/components/o-auth-provider-button/OAuthProviderButton.d.ts +1 -0
  157. package/web-dist/components/o-auth-provider-button/OAuthProviderButton.js +21 -16
  158. package/web-dist/components/o-auth-provider-list/OAuthProviderList.d.ts +1 -0
  159. package/web-dist/components/o-auth-provider-list/OAuthProviderList.js +21 -16
  160. package/web-dist/components/otp-form/OtpForm.d.ts +1 -0
  161. package/web-dist/components/otp-form/OtpForm.js +21 -16
  162. package/web-dist/components/pagination/Pagination.js +6 -6
  163. package/web-dist/components/palette-item/PaletteItem.js +9 -9
  164. package/web-dist/components/popover-menu/PopoverMenu.js +3 -3
  165. package/web-dist/components/post-card/PostCard.js +7 -7
  166. package/web-dist/components/product-card/ProductCard.js +7 -7
  167. package/web-dist/components/progress/Progress.js +2 -2
  168. package/web-dist/components/progress-ring/ProgressRing.js +2 -2
  169. package/web-dist/components/radio/Radio.js +4 -4
  170. package/web-dist/components/radio-group/RadioGroup.js +4 -4
  171. package/web-dist/components/reader-surface/ReaderSurface.js +11 -11
  172. package/web-dist/components/scan-overlay/ScanOverlay.js +8 -8
  173. package/web-dist/components/screen-section/ScreenSection.js +2 -2
  174. package/web-dist/components/search-input/SearchInput.js +4 -4
  175. package/web-dist/components/section-header/SectionHeader.js +2 -2
  176. package/web-dist/components/section-list/SectionList.js +5 -5
  177. package/web-dist/components/select/Select.js +4 -4
  178. package/web-dist/components/sign-in-form/SignInForm.d.ts +1 -0
  179. package/web-dist/components/sign-in-form/SignInForm.js +21 -16
  180. package/web-dist/components/sign-up-form/SignUpForm.d.ts +1 -0
  181. package/web-dist/components/sign-up-form/SignUpForm.js +21 -16
  182. package/web-dist/components/skeleton/Skeleton.js +10 -10
  183. package/web-dist/components/skeleton-card/SkeletonCard.js +10 -10
  184. package/web-dist/components/skeleton-list/SkeletonList.js +10 -10
  185. package/web-dist/components/skeleton-text/SkeletonText.js +10 -10
  186. package/web-dist/components/switch/Switch.js +3 -3
  187. package/web-dist/components/tab/Tab.js +2 -2
  188. package/web-dist/components/tab-list/TabList.js +2 -2
  189. package/web-dist/components/tab-panel/TabPanel.js +2 -2
  190. package/web-dist/components/tabs/Tabs.js +2 -2
  191. package/web-dist/components/text/Text.js +3 -3
  192. package/web-dist/components/text-input/TextInput.js +4 -4
  193. package/web-dist/components/time-picker/TimePicker.js +10 -10
  194. package/web-dist/components/timeline/Timeline.js +4 -4
  195. package/web-dist/components/toast/Toast.js +3 -3
  196. package/web-dist/components/toast-provider/ToastProvider.js +3 -3
  197. package/web-dist/components/toolbar/Toolbar.js +7 -7
  198. package/web-dist/components/tree-item/TreeItem.js +10 -9
  199. package/web-dist/components/tree-view/TreeView.d.ts +1 -0
  200. package/web-dist/components/tree-view/TreeView.js +5 -2
  201. package/web-dist/components/uploader/Uploader.js +15 -15
  202. package/web-dist/manifest.json +444 -384
  203. package/web-dist/runtime/ZoraProvider.js +3 -3
@@ -0,0 +1,202 @@
1
+ import React from 'react';
2
+ import { Platform } from 'react-native';
3
+
4
+ import type { AuthScreenProps } from '../../../../types/auth';
5
+ import { KeyboardAvoidingView } from '../../../keyboard-avoiding-view/public';
6
+ import { Divider, ScrollView, View } from '../../../layout/public';
7
+ import { Surface } from '../../../surface/public';
8
+ import { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThemeScope';
9
+ import { Text } from '../../../typography/public';
10
+ import { OAuthProviderList } from './OAuthProviderList';
11
+ import { SignInForm } from './SignInForm';
12
+ import { SignUpForm } from './SignUpForm';
13
+
14
+ /***
15
+ * Reusable authentication-screen composition for sign-in and sign-up flows.
16
+ *
17
+ * Owns keyboard-safe responsive layout, auth surface presentation, OAuth separation, and
18
+ * sign-in/sign-up form composition while consumers retain routing and authentication orchestration.
19
+ */
20
+ export const AuthScreen = withZoraThemeScope(AuthScreenInner);
21
+
22
+ /*** Render the themed authentication screen while preserving consumer-owned callbacks and state. */
23
+ function AuthScreenInner({
24
+ themeId: _themeId,
25
+ mode: _themeMode,
26
+ interactionPolicy,
27
+ authMode,
28
+ title,
29
+ description,
30
+ info,
31
+ error,
32
+ loading = false,
33
+ disabled = false,
34
+ identifiers,
35
+ identifierLabel,
36
+ signUpFields,
37
+ oauthProviders = [],
38
+ oauthSeparatorLabel = 'or continue with password',
39
+ onModeChange,
40
+ onOAuthProviderPress,
41
+ onSignInSubmit,
42
+ onSignUpSubmit,
43
+ testID,
44
+ }: AuthScreenProps) {
45
+ const effectiveTitle = title ?? (authMode === 'signIn' ? 'Sign in' : 'Create account');
46
+ const hasOAuth = oauthProviders.length > 0;
47
+
48
+ return (
49
+ <KeyboardAvoidingView
50
+ behavior={Platform.select({ android: 'height', ios: 'padding' })}
51
+ interactionPolicy={interactionPolicy}
52
+ style={{ flex: 1 }}
53
+ >
54
+ <ScrollView
55
+ bg="background"
56
+ contentContainerStyle={{ flexGrow: 1 }}
57
+ flex={1}
58
+ interactionPolicy={interactionPolicy}
59
+ keyboardShouldPersistTaps="handled"
60
+ >
61
+ <View
62
+ align="center"
63
+ flex={1}
64
+ interactionPolicy={interactionPolicy}
65
+ justify="center"
66
+ px={{ base: 'm', md: 'xl' }}
67
+ py="xl"
68
+ >
69
+ <Surface
70
+ gap="m"
71
+ maxWidth={560}
72
+ p={{ base: 'l', md: 'xl' }}
73
+ radius="l"
74
+ testID={testID}
75
+ variant="outline"
76
+ width="100%"
77
+ >
78
+ <View gap="xs" interactionPolicy={interactionPolicy}>
79
+ <Text variant="lead" weight="semiBold">
80
+ {effectiveTitle}
81
+ </Text>
82
+ {description ? (
83
+ <Text emphasis="muted" variant="bodySmall">
84
+ {description}
85
+ </Text>
86
+ ) : null}
87
+ </View>
88
+
89
+ {hasOAuth ? (
90
+ <>
91
+ <OAuthProviderList
92
+ disabled={disabled || loading}
93
+ interactionPolicy={interactionPolicy}
94
+ onProviderPress={onOAuthProviderPress}
95
+ providers={oauthProviders}
96
+ testID={testID ? `${testID}-oauth` : undefined}
97
+ />
98
+ <View align="center" direction="row" gap="s" interactionPolicy={interactionPolicy}>
99
+ <View flex={1} interactionPolicy={interactionPolicy}>
100
+ <Divider interactionPolicy={interactionPolicy} />
101
+ </View>
102
+ <Text emphasis="muted" variant="bodySmall">
103
+ {oauthSeparatorLabel}
104
+ </Text>
105
+ <View flex={1} interactionPolicy={interactionPolicy}>
106
+ <Divider interactionPolicy={interactionPolicy} />
107
+ </View>
108
+ </View>
109
+ </>
110
+ ) : null}
111
+
112
+ <AuthScreenForm
113
+ authMode={authMode}
114
+ disabled={disabled}
115
+ error={error}
116
+ identifierLabel={identifierLabel}
117
+ identifiers={identifiers}
118
+ interactionPolicy={interactionPolicy}
119
+ loading={loading}
120
+ onModeChange={onModeChange}
121
+ onSignInSubmit={onSignInSubmit}
122
+ onSignUpSubmit={onSignUpSubmit}
123
+ signUpFields={signUpFields}
124
+ testID={testID ? `${testID}-form` : undefined}
125
+ />
126
+
127
+ {info ? (
128
+ <Text color="success" variant="bodySmall">
129
+ {info}
130
+ </Text>
131
+ ) : null}
132
+ </Surface>
133
+ </View>
134
+ </ScrollView>
135
+ </KeyboardAvoidingView>
136
+ );
137
+ }
138
+
139
+ type AuthScreenFormProps = Pick<
140
+ AuthScreenProps,
141
+ | 'authMode'
142
+ | 'disabled'
143
+ | 'error'
144
+ | 'identifierLabel'
145
+ | 'identifiers'
146
+ | 'interactionPolicy'
147
+ | 'loading'
148
+ | 'onModeChange'
149
+ | 'onSignInSubmit'
150
+ | 'onSignUpSubmit'
151
+ | 'signUpFields'
152
+ | 'testID'
153
+ >;
154
+
155
+ /*** Render the active ZORA auth form and translate form-switch actions into the shared mode boundary. */
156
+ function AuthScreenForm({
157
+ authMode,
158
+ disabled,
159
+ error,
160
+ identifierLabel,
161
+ identifiers,
162
+ interactionPolicy,
163
+ loading,
164
+ onModeChange,
165
+ onSignInSubmit,
166
+ onSignUpSubmit,
167
+ signUpFields,
168
+ testID,
169
+ }: AuthScreenFormProps) {
170
+ if (authMode === 'signIn') {
171
+ return (
172
+ <SignInForm
173
+ disabled={disabled}
174
+ error={error}
175
+ identifierLabel={identifierLabel}
176
+ identifiers={identifiers}
177
+ interactionPolicy={interactionPolicy}
178
+ loading={loading}
179
+ onSignUp={onModeChange ? () => onModeChange('signUp') : undefined}
180
+ onSubmit={onSignInSubmit}
181
+ signUpLabel="Need an account? Sign up"
182
+ submitLabel="Sign in"
183
+ testID={testID}
184
+ />
185
+ );
186
+ }
187
+
188
+ return (
189
+ <SignUpForm
190
+ disabled={disabled}
191
+ error={error}
192
+ fields={signUpFields}
193
+ interactionPolicy={interactionPolicy}
194
+ loading={loading}
195
+ onSignIn={onModeChange ? () => onModeChange('signIn') : undefined}
196
+ onSubmit={onSignUpSubmit}
197
+ signInLabel="Already have an account? Sign in"
198
+ submitLabel="Create account"
199
+ testID={testID}
200
+ />
201
+ );
202
+ }
@@ -0,0 +1,114 @@
1
+ import type { ZoraComponentMeta } from '../../types/authoring';
2
+
3
+ export const authScreenMeta = {
4
+ name: 'AuthScreen',
5
+ category: 'pattern',
6
+ description:
7
+ 'Presents a complete responsive sign-in or sign-up screen while leaving authentication orchestration to the consumer.',
8
+ directManifestNode: true,
9
+ allowedChildren: [],
10
+ blueprint: {
11
+ label: 'Auth screen',
12
+ defaultProps: {
13
+ authMode: 'signIn',
14
+ identifiers: ['email'],
15
+ loading: false,
16
+ disabled: false,
17
+ },
18
+ },
19
+ events: {
20
+ modeChange: {
21
+ label: 'Mode change',
22
+ eventType: 'authScreen.modeChange',
23
+ payloadFields: [{ path: 'mode', type: 'string', label: 'Mode' }],
24
+ },
25
+ oauthProviderPress: {
26
+ label: 'OAuth provider press',
27
+ eventType: 'authScreen.oauthProviderPress',
28
+ payloadFields: [{ path: 'providerId', type: 'string', label: 'Provider ID' }],
29
+ },
30
+ signInSubmit: {
31
+ label: 'Sign-in submit',
32
+ eventType: 'authScreen.signInSubmit',
33
+ payloadFields: [
34
+ { path: 'identifier', type: 'string', label: 'Identifier' },
35
+ { path: 'identifierKind', type: 'string', label: 'Identifier kind' },
36
+ { path: 'secret', type: 'string', label: 'Secret' },
37
+ ],
38
+ },
39
+ signUpSubmit: {
40
+ label: 'Sign-up submit',
41
+ eventType: 'authScreen.signUpSubmit',
42
+ payloadFields: [{ path: 'values', type: 'record', label: 'Values' }],
43
+ },
44
+ },
45
+ props: {
46
+ authMode: {
47
+ type: 'enum',
48
+ category: 'Authentication',
49
+ label: 'Auth mode',
50
+ enum: ['signIn', 'signUp'],
51
+ default: 'signIn',
52
+ },
53
+ title: { type: 'string', category: 'Content', label: 'Title' },
54
+ description: { type: 'string', category: 'Content', label: 'Description' },
55
+ info: { type: 'string', category: 'State', label: 'Info' },
56
+ error: { type: 'string', category: 'State', label: 'Error' },
57
+ loading: { type: 'boolean', category: 'State', label: 'Loading', default: false },
58
+ disabled: { type: 'boolean', category: 'State', label: 'Disabled', default: false },
59
+ identifiers: {
60
+ type: 'array',
61
+ category: 'Authentication',
62
+ label: 'Identifiers',
63
+ default: ['email'],
64
+ },
65
+ identifierLabel: { type: 'string', category: 'Content', label: 'Identifier label' },
66
+ signUpFields: {
67
+ type: 'array',
68
+ category: 'Authentication',
69
+ label: 'Sign-up fields',
70
+ itemSchema: [
71
+ { key: 'name', schema: { type: 'string', category: 'Identity', label: 'Name' } },
72
+ { key: 'label', schema: { type: 'string', category: 'Content', label: 'Label' } },
73
+ {
74
+ key: 'type',
75
+ schema: {
76
+ type: 'enum',
77
+ category: 'Authentication',
78
+ label: 'Type',
79
+ enum: ['email', 'number', 'otp', 'password', 'tel', 'text', 'url'],
80
+ },
81
+ },
82
+ {
83
+ key: 'placeholder',
84
+ schema: { type: 'string', category: 'Content', label: 'Placeholder' },
85
+ },
86
+ {
87
+ key: 'required',
88
+ schema: { type: 'boolean', category: 'Validation', label: 'Required' },
89
+ },
90
+ {
91
+ key: 'disabled',
92
+ schema: { type: 'boolean', category: 'State', label: 'Disabled' },
93
+ },
94
+ ],
95
+ },
96
+ oauthProviders: {
97
+ type: 'array',
98
+ category: 'Authentication',
99
+ label: 'OAuth providers',
100
+ itemSchema: [
101
+ { key: 'id', schema: { type: 'string', category: 'Identity', label: 'Provider ID' } },
102
+ { key: 'label', schema: { type: 'string', category: 'Content', label: 'Label' } },
103
+ { key: 'disabled', schema: { type: 'boolean', category: 'State', label: 'Disabled' } },
104
+ { key: 'loading', schema: { type: 'boolean', category: 'State', label: 'Loading' } },
105
+ ],
106
+ },
107
+ oauthSeparatorLabel: {
108
+ type: 'string',
109
+ category: 'Content',
110
+ label: 'OAuth separator label',
111
+ default: 'or continue with password',
112
+ },
113
+ },
114
+ } as const satisfies ZoraComponentMeta;
@@ -1,5 +1,6 @@
1
1
  import { expect, test } from 'bun:test';
2
2
 
3
+ import { authScreenMeta } from './authScreenMeta';
3
4
  import { forgotPasswordFormMeta } from './forgotPasswordFormMeta';
4
5
  import { oauthProviderButtonMeta } from './oauthProviderButtonMeta';
5
6
  import { oauthProviderListMeta } from './oauthProviderListMeta';
@@ -8,6 +9,7 @@ import { signInFormMeta } from './signInFormMeta';
8
9
  import { signUpFormMeta } from './signUpFormMeta';
9
10
 
10
11
  const AUTH_MANIFEST_ELEMENTS = {
12
+ AuthScreen: authScreenMeta,
11
13
  ForgotPasswordForm: forgotPasswordFormMeta,
12
14
  OAuthProviderButton: oauthProviderButtonMeta,
13
15
  OAuthProviderList: oauthProviderListMeta,
@@ -25,6 +27,10 @@ test('auth solutions are direct manifest leaf nodes with authoring schemas', ()
25
27
  });
26
28
 
27
29
  test('auth solution events expose their actionable boundaries', () => {
30
+ expect(authScreenMeta.events.modeChange.eventType).toBe('authScreen.modeChange');
31
+ expect(authScreenMeta.events.oauthProviderPress.payloadFields).toEqual([
32
+ { path: 'providerId', type: 'string', label: 'Provider ID' },
33
+ ]);
28
34
  expect(signInFormMeta.events.submit.payloadFields).toContainEqual({
29
35
  path: 'secret',
30
36
  type: 'string',
@@ -1,6 +1,8 @@
1
1
  export type {
2
2
  AuthFormBaseProps,
3
3
  AuthIdentifierKind,
4
+ AuthScreenMode,
5
+ AuthScreenProps,
4
6
  ForgotPasswordFormProps,
5
7
  ForgotPasswordFormValues,
6
8
  OAuthProviderButtonProps,
@@ -16,6 +18,7 @@ export type {
16
18
  SignUpFormProps,
17
19
  SignUpFormValues,
18
20
  } from '../../types/auth';
21
+ export { AuthScreen } from './adapters/inbound/AuthScreen';
19
22
  export { ForgotPasswordForm } from './adapters/inbound/ForgotPasswordForm';
20
23
  export { OAuthProviderButton } from './adapters/inbound/OAuthProviderButton';
21
24
  export { OAuthProviderList } from './adapters/inbound/OAuthProviderList';
@@ -6,6 +6,7 @@ import { Accordion, AccordionItem } from '../accordion/public';
6
6
  import { ActivityIndicator } from '../activity-indicator/public';
7
7
  import { AppBar } from '../app-bar/public';
8
8
  import {
9
+ AuthScreen,
9
10
  ForgotPasswordForm,
10
11
  OAuthProviderButton,
11
12
  OAuthProviderList,
@@ -175,6 +176,7 @@ const _ZORA_COMPONENT_REGISTRY = {
175
176
  AppShell,
176
177
  Screen,
177
178
  ScreenSection,
179
+ AuthScreen,
178
180
  ForgotPasswordForm,
179
181
  OAuthProviderButton,
180
182
  OAuthProviderList,
@@ -166,6 +166,7 @@ describe('ZORA_COMPONENT_META invariants', () => {
166
166
  test('direct manifest node leaf/container rules', () => {
167
167
  const expectedLeafNodes = new Set([
168
168
  'ActivityIndicator',
169
+ 'AuthScreen',
169
170
  'ForgotPasswordForm',
170
171
  'OAuthProviderButton',
171
172
  'OAuthProviderList',
@@ -3,6 +3,7 @@ import { accordionItemMeta } from '../accordion/accordionItemMeta';
3
3
  import { accordionMeta } from '../accordion/accordionMeta';
4
4
  import { activityIndicatorMeta } from '../activity-indicator/activityIndicatorMeta';
5
5
  import { appBarMeta } from '../app-bar/appBarMeta';
6
+ import { authScreenMeta } from '../auth/authScreenMeta';
6
7
  import { forgotPasswordFormMeta } from '../auth/forgotPasswordFormMeta';
7
8
  import { oauthProviderButtonMeta } from '../auth/oauthProviderButtonMeta';
8
9
  import { oauthProviderListMeta } from '../auth/oauthProviderListMeta';
@@ -178,6 +179,7 @@ export const ZORA_COMPONENT_META: ZoraComponentMetaRegistry = finalizeFeatureMet
178
179
  AppShell: appShellMeta,
179
180
  Screen: screenMeta,
180
181
  ScreenSection: screenSectionMeta,
182
+ AuthScreen: authScreenMeta,
181
183
  ForgotPasswordForm: forgotPasswordFormMeta,
182
184
  OAuthProviderButton: oauthProviderButtonMeta,
183
185
  OAuthProviderList: oauthProviderListMeta,
@@ -54,11 +54,12 @@ function TreeItemInner<TId extends string = string>({
54
54
  });
55
55
  }
56
56
 
57
+ const nodeIcon = isExpanded ? (node.expandedIcon ?? node.icon) : node.icon;
57
58
  const listItemProps = {
58
59
  title: node.label,
59
60
  leading:
60
- expansionIndicator === 'folder' || node.icon === undefined ? undefined : (
61
- <Icon {...node.icon} size="s" />
61
+ expansionIndicator === 'folder' || nodeIcon === undefined ? undefined : (
62
+ <Icon {...nodeIcon} size={12} />
62
63
  ),
63
64
  meta: node.meta,
64
65
  disabled: node.disabled,
@@ -17,7 +17,13 @@ export function TreeItemRow<TId extends string>(props: TreeItemRowProps<TId>) {
17
17
  selected,
18
18
  expanded,
19
19
  hasChildren,
20
- }) ?? <TreeItemDefaultContent node={node} showIcon={props.expansionIndicator === 'chevron'} />;
20
+ }) ?? (
21
+ <TreeItemDefaultContent
22
+ expanded={expanded}
23
+ node={node}
24
+ showIcon={props.expansionIndicator === 'chevron'}
25
+ />
26
+ );
21
27
 
22
28
  return (
23
29
  <>
@@ -61,17 +67,20 @@ interface TreeItemRowProps<TId extends string> {
61
67
 
62
68
  /*** Render the default browser tree-row label, icon, and metadata. */
63
69
  function TreeItemDefaultContent<TId extends string>({
70
+ expanded,
64
71
  node,
65
72
  showIcon,
66
73
  }: {
74
+ readonly expanded: boolean;
67
75
  readonly node: TreeItemNode<TId>;
68
76
  readonly showIcon: boolean;
69
77
  }) {
78
+ const icon = expanded ? (node.expandedIcon ?? node.icon) : node.icon;
70
79
  return (
71
80
  <>
72
- {!showIcon || node.icon === undefined ? null : (
81
+ {!showIcon || icon === undefined ? null : (
73
82
  <span aria-hidden="true" style={ICON_STYLE}>
74
- {node.icon}
83
+ {icon}
75
84
  </span>
76
85
  )}
77
86
  <span style={LABEL_STYLE}>{node.label}</span>
@@ -221,3 +221,22 @@ test('supports folder/file indicators without duplicating supplied row icons', (
221
221
  expect(markup).not.toContain('duplicate-icon');
222
222
  expect(markup.match(/<svg/g)?.length).toBe(2);
223
223
  });
224
+
225
+ test('renders the expanded node icon while a chevron node is open', () => {
226
+ const node = {
227
+ id: 'src',
228
+ label: 'src',
229
+ icon: <span>closed-folder</span>,
230
+ expandedIcon: <span>open-folder</span>,
231
+ children: [{ id: 'file', label: 'file.ts' }],
232
+ };
233
+ const collapsed = renderToStaticMarkup(<TreeView expansionIndicator="chevron" nodes={[node]} />);
234
+ const expanded = renderToStaticMarkup(
235
+ <TreeView expansionIndicator="chevron" defaultExpandedIds={['src']} nodes={[node]} />,
236
+ );
237
+
238
+ expect(collapsed).toContain('closed-folder');
239
+ expect(collapsed).not.toContain('open-folder');
240
+ expect(expanded).toContain('open-folder');
241
+ expect(expanded).not.toContain('closed-folder');
242
+ });
@@ -8,6 +8,7 @@ export interface TreeItemNode<TId extends string = string> {
8
8
  readonly id: TId;
9
9
  readonly label: React.ReactNode;
10
10
  readonly icon?: React.ReactNode;
11
+ readonly expandedIcon?: React.ReactNode;
11
12
  readonly children?: readonly TreeItemNode<TId>[];
12
13
  readonly disabled?: boolean;
13
14
  readonly meta?: React.ReactNode;
package/src/index.ts CHANGED
@@ -16,6 +16,8 @@ export { AppBar } from './features/app-bar/public';
16
16
  export type {
17
17
  AuthFormBaseProps,
18
18
  AuthIdentifierKind,
19
+ AuthScreenMode,
20
+ AuthScreenProps,
19
21
  ForgotPasswordFormProps,
20
22
  ForgotPasswordFormValues,
21
23
  OAuthProviderButtonProps,
@@ -32,6 +34,7 @@ export type {
32
34
  SignUpFormValues,
33
35
  } from './features/auth/public';
34
36
  export {
37
+ AuthScreen,
35
38
  DEFAULT_OAUTH_PROVIDER_ICONS,
36
39
  ForgotPasswordForm,
37
40
  OAuthProviderButton,
@@ -63,6 +63,7 @@ const REQUIRED_SHOWCASE_COVERAGE = {
63
63
  features: ['Uploader', 'BottomSheet', 'FlatList', 'SectionList'],
64
64
  layouts: ['AppShell', 'Screen', 'ScreenSection', 'ScrollView'],
65
65
  patterns: [
66
+ 'AuthScreen',
66
67
  'ForgotPasswordForm',
67
68
  'OtpForm',
68
69
  'SignInForm',
package/src/types/auth.ts CHANGED
@@ -7,6 +7,27 @@ import type { FormFieldConfig, FormValues } from './form';
7
7
 
8
8
  export type AuthIdentifierKind = 'email' | 'phone' | 'username';
9
9
 
10
+ export type AuthScreenMode = 'signIn' | 'signUp';
11
+
12
+ export interface AuthScreenProps extends ZoraBaseProps {
13
+ authMode: AuthScreenMode;
14
+ title?: React.ReactNode;
15
+ description?: React.ReactNode;
16
+ info?: React.ReactNode;
17
+ error?: React.ReactNode;
18
+ loading?: boolean;
19
+ disabled?: boolean;
20
+ identifiers?: readonly AuthIdentifierKind[];
21
+ identifierLabel?: React.ReactNode;
22
+ signUpFields?: readonly SignUpFormField[];
23
+ oauthProviders?: readonly OAuthProviderItem[];
24
+ oauthSeparatorLabel?: React.ReactNode;
25
+ onModeChange?: (mode: AuthScreenMode) => void | Promise<void>;
26
+ onOAuthProviderPress?: (providerId: string) => void | Promise<void>;
27
+ onSignInSubmit?: (values: SignInFormValues) => void | Promise<void>;
28
+ onSignUpSubmit?: (values: SignUpFormValues) => void | Promise<void>;
29
+ }
30
+
10
31
  export interface AuthFormBaseProps extends ZoraBaseProps {
11
32
  loading?: boolean;
12
33
  disabled?: boolean;
@@ -8,6 +8,7 @@ export interface TreeItemNode<TId extends string = string> {
8
8
  id: TId;
9
9
  label: ReactNode;
10
10
  icon?: ButtonIconSpec;
11
+ expandedIcon?: ButtonIconSpec;
11
12
  children?: readonly TreeItemNode<TId>[];
12
13
  disabled?: boolean;
13
14
  meta?: ReactNode;
@@ -4,7 +4,7 @@ import {
4
4
  } from "./Accordion-7hn324r1.js";
5
5
  import {
6
6
  Button2
7
- } from "./Accordion-dp638q63.js";
7
+ } from "./Accordion-yms7x22j.js";
8
8
  import {
9
9
  withZoraThemeScope
10
10
  } from "./Accordion-13y3zx87.js";
@@ -13,13 +13,13 @@ import {
13
13
  } from "./Accordion-01e56hb5.js";
14
14
  import {
15
15
  Card2
16
- } from "./Accordion-fm3jxs1f.js";
16
+ } from "./Accordion-z1trs7s1.js";
17
17
  import {
18
- Text2
19
- } from "./Accordion-rx2gzadh.js";
18
+ Text3
19
+ } from "./Accordion-46vwm9xv.js";
20
20
  import {
21
21
  Badge2
22
- } from "./Accordion-x13vca75.js";
22
+ } from "./Accordion-cqgbx1pw.js";
23
23
  import {
24
24
  useZoraTheme2
25
25
  } from "./Accordion-7zfskq1s.js";
@@ -82,7 +82,7 @@ function CameraPermissionViewInner({
82
82
  children: /* @__PURE__ */ jsxs(View2, {
83
83
  gap: "m",
84
84
  children: [
85
- /* @__PURE__ */ jsxs(Text2, {
85
+ /* @__PURE__ */ jsxs(Text3, {
86
86
  emphasis: "muted",
87
87
  variant: "bodySmall",
88
88
  children: [
@@ -167,13 +167,13 @@ function ScanOverlayInner({
167
167
  /* @__PURE__ */ jsxs2(View2, {
168
168
  gap: "xs",
169
169
  children: [
170
- /* @__PURE__ */ jsx2(Text2, {
170
+ /* @__PURE__ */ jsx2(Text3, {
171
171
  align: "center",
172
172
  variant: "label",
173
173
  weight: "semiBold",
174
174
  children: title
175
175
  }),
176
- /* @__PURE__ */ jsx2(Text2, {
176
+ /* @__PURE__ */ jsx2(Text3, {
177
177
  align: "center",
178
178
  emphasis: "muted",
179
179
  variant: "bodySmall",
@@ -304,7 +304,7 @@ function BarcodeScannerViewInner({
304
304
  children ? /* @__PURE__ */ jsx3(View2, {
305
305
  children
306
306
  }) : null,
307
- /* @__PURE__ */ jsx3(Text2, {
307
+ /* @__PURE__ */ jsx3(Text3, {
308
308
  emphasis: "muted",
309
309
  variant: "caption",
310
310
  children: "Native scanning belongs to an app adapter such as expo-camera. ZORA owns this visible scanner surface."
@@ -577,7 +577,7 @@ var textThemeRecipeMeta = {
577
577
 
578
578
  // src/features/typography/adapters/inbound/Text.tsx
579
579
  import { jsx as jsx2 } from "react/jsx-runtime";
580
- var Text2 = withZoraThemeScope(TextInner);
580
+ var Text3 = withZoraThemeScope(TextInner);
581
581
  var textLayoutStyle = {
582
582
  flexShrink: 1,
583
583
  maxWidth: "100%",
@@ -656,4 +656,4 @@ function TextInner({
656
656
  children: content
657
657
  });
658
658
  }
659
- export { Heading2, Text2 };
659
+ export { Heading2, Text3 };
@@ -24,8 +24,8 @@ import {
24
24
  } from "./Accordion-01e56hb5.js";
25
25
  import {
26
26
  Heading2,
27
- Text2
28
- } from "./Accordion-rx2gzadh.js";
27
+ Text3
28
+ } from "./Accordion-46vwm9xv.js";
29
29
  import {
30
30
  resolveOverlayAnimation
31
31
  } from "./Accordion-2d8xn32m.js";
@@ -158,7 +158,7 @@ function DialogInner({
158
158
  level: 3,
159
159
  children: title
160
160
  }) : null,
161
- description !== undefined ? /* @__PURE__ */ jsx2(Text2, {
161
+ description !== undefined ? /* @__PURE__ */ jsx2(Text3, {
162
162
  emphasis: "muted",
163
163
  variant: "bodySmall",
164
164
  children: description