@ankhorage/zora 12.1.0 → 14.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.
Files changed (263) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +11 -5
  3. package/dist/features/accordion/accordionItemMeta.d.ts +53 -0
  4. package/dist/features/accordion/accordionItemMeta.d.ts.map +1 -0
  5. package/dist/features/accordion/accordionItemMeta.js +45 -0
  6. package/dist/features/accordion/accordionItemMeta.js.map +1 -0
  7. package/dist/features/accordion/accordionMeta.d.ts +36 -0
  8. package/dist/features/accordion/accordionMeta.d.ts.map +1 -0
  9. package/dist/features/accordion/accordionMeta.js +33 -0
  10. package/dist/features/accordion/accordionMeta.js.map +1 -0
  11. package/dist/features/accordion/adapters/inbound/Accordion.d.ts +5 -0
  12. package/dist/features/accordion/adapters/inbound/Accordion.d.ts.map +1 -0
  13. package/dist/features/accordion/adapters/inbound/Accordion.js +41 -0
  14. package/dist/features/accordion/adapters/inbound/Accordion.js.map +1 -0
  15. package/dist/features/accordion/adapters/inbound/AccordionItem.d.ts +5 -0
  16. package/dist/features/accordion/adapters/inbound/AccordionItem.d.ts.map +1 -0
  17. package/dist/features/accordion/adapters/inbound/AccordionItem.js +52 -0
  18. package/dist/features/accordion/adapters/inbound/AccordionItem.js.map +1 -0
  19. package/dist/features/accordion/composition/AccordionPresentationContext.d.ts +4 -0
  20. package/dist/features/accordion/composition/AccordionPresentationContext.d.ts.map +1 -0
  21. package/dist/features/accordion/composition/AccordionPresentationContext.js +3 -0
  22. package/dist/features/accordion/composition/AccordionPresentationContext.js.map +1 -0
  23. package/dist/features/accordion/public.d.ts +4 -0
  24. package/dist/features/accordion/public.d.ts.map +1 -0
  25. package/dist/features/accordion/public.js +3 -0
  26. package/dist/features/accordion/public.js.map +1 -0
  27. package/dist/features/bottom-sheet/bottomSheetMeta.d.ts +1 -1
  28. package/dist/features/card/cardMeta.d.ts +1 -1
  29. package/dist/features/card/mediaCardMeta.d.ts +1 -1
  30. package/dist/features/card/postCardMeta.d.ts +1 -1
  31. package/dist/features/date-picker/adapters/inbound/DatePicker.d.ts +1 -6
  32. package/dist/features/date-picker/adapters/inbound/DatePicker.d.ts.map +1 -1
  33. package/dist/features/date-picker/adapters/inbound/DatePicker.js +1 -175
  34. package/dist/features/date-picker/adapters/inbound/DatePicker.js.map +1 -1
  35. package/dist/features/date-picker/adapters/inbound/DatePicker.native.d.ts +5 -0
  36. package/dist/features/date-picker/adapters/inbound/DatePicker.native.d.ts.map +1 -0
  37. package/dist/features/date-picker/adapters/inbound/DatePicker.native.js +27 -0
  38. package/dist/features/date-picker/adapters/inbound/DatePicker.native.js.map +1 -0
  39. package/dist/features/date-picker/adapters/inbound/DatePicker.web.d.ts +5 -0
  40. package/dist/features/date-picker/adapters/inbound/DatePicker.web.d.ts.map +1 -0
  41. package/dist/features/date-picker/adapters/inbound/DatePicker.web.js +25 -0
  42. package/dist/features/date-picker/adapters/inbound/DatePicker.web.js.map +1 -0
  43. package/dist/features/date-picker/composition/DatePickerContent.d.ts +10 -0
  44. package/dist/features/date-picker/composition/DatePickerContent.d.ts.map +1 -0
  45. package/dist/features/date-picker/composition/DatePickerContent.js +129 -0
  46. package/dist/features/date-picker/composition/DatePickerContent.js.map +1 -0
  47. package/dist/features/date-picker/composition/DatePickerField.d.ts +9 -0
  48. package/dist/features/date-picker/composition/DatePickerField.d.ts.map +1 -0
  49. package/dist/features/date-picker/composition/DatePickerField.js +21 -0
  50. package/dist/features/date-picker/composition/DatePickerField.js.map +1 -0
  51. package/dist/features/date-picker/composition/DatePickerTrigger.d.ts +9 -0
  52. package/dist/features/date-picker/composition/DatePickerTrigger.d.ts.map +1 -0
  53. package/dist/features/date-picker/composition/DatePickerTrigger.js +18 -0
  54. package/dist/features/date-picker/composition/DatePickerTrigger.js.map +1 -0
  55. package/dist/features/gradient/gradientMeta.d.ts +1 -1
  56. package/dist/features/keyboard-avoiding-view/keyboardAvoidingViewMeta.d.ts +1 -1
  57. package/dist/features/layout/boxMeta.d.ts +1 -1
  58. package/dist/features/layout/containerMeta.d.ts +1 -1
  59. package/dist/features/layout/gridMeta.d.ts +1 -1
  60. package/dist/features/layout/stackMeta.d.ts +1 -1
  61. package/dist/features/list/flatListMeta.d.ts +1 -1
  62. package/dist/features/list/sectionListMeta.d.ts +1 -1
  63. package/dist/features/surface/surfaceMeta.d.ts +1 -1
  64. package/dist/features/time-picker/adapters/inbound/TimePicker.d.ts +1 -6
  65. package/dist/features/time-picker/adapters/inbound/TimePicker.d.ts.map +1 -1
  66. package/dist/features/time-picker/adapters/inbound/TimePicker.js +1 -116
  67. package/dist/features/time-picker/adapters/inbound/TimePicker.js.map +1 -1
  68. package/dist/features/time-picker/adapters/inbound/TimePicker.native.d.ts +5 -0
  69. package/dist/features/time-picker/adapters/inbound/TimePicker.native.d.ts.map +1 -0
  70. package/dist/features/time-picker/adapters/inbound/TimePicker.native.js +26 -0
  71. package/dist/features/time-picker/adapters/inbound/TimePicker.native.js.map +1 -0
  72. package/dist/features/time-picker/adapters/inbound/TimePicker.web.d.ts +5 -0
  73. package/dist/features/time-picker/adapters/inbound/TimePicker.web.d.ts.map +1 -0
  74. package/dist/features/time-picker/adapters/inbound/TimePicker.web.js +24 -0
  75. package/dist/features/time-picker/adapters/inbound/TimePicker.web.js.map +1 -0
  76. package/dist/features/time-picker/composition/TimePickerContent.d.ts +10 -0
  77. package/dist/features/time-picker/composition/TimePickerContent.d.ts.map +1 -0
  78. package/dist/features/time-picker/composition/TimePickerContent.js +78 -0
  79. package/dist/features/time-picker/composition/TimePickerContent.js.map +1 -0
  80. package/dist/features/time-picker/composition/TimePickerField.d.ts +9 -0
  81. package/dist/features/time-picker/composition/TimePickerField.d.ts.map +1 -0
  82. package/dist/features/time-picker/composition/TimePickerField.js +21 -0
  83. package/dist/features/time-picker/composition/TimePickerField.js.map +1 -0
  84. package/dist/features/time-picker/composition/TimePickerTrigger.d.ts +8 -0
  85. package/dist/features/time-picker/composition/TimePickerTrigger.d.ts.map +1 -0
  86. package/dist/features/time-picker/composition/TimePickerTrigger.js +9 -0
  87. package/dist/features/time-picker/composition/TimePickerTrigger.js.map +1 -0
  88. package/dist/features/toast/adapters/inbound/Toast.d.ts +5 -0
  89. package/dist/features/toast/adapters/inbound/Toast.d.ts.map +1 -0
  90. package/dist/features/toast/adapters/inbound/Toast.js +10 -0
  91. package/dist/features/toast/adapters/inbound/Toast.js.map +1 -0
  92. package/dist/features/toast/adapters/inbound/ToastProvider.d.ts +5 -0
  93. package/dist/features/toast/adapters/inbound/ToastProvider.d.ts.map +1 -0
  94. package/dist/features/toast/adapters/inbound/ToastProvider.js +7 -0
  95. package/dist/features/toast/adapters/inbound/ToastProvider.js.map +1 -0
  96. package/dist/features/toast/public.d.ts +5 -0
  97. package/dist/features/toast/public.d.ts.map +1 -0
  98. package/dist/features/toast/public.js +4 -0
  99. package/dist/features/toast/public.js.map +1 -0
  100. package/dist/features/toast/toastMeta.d.ts +9 -0
  101. package/dist/features/toast/toastMeta.d.ts.map +1 -0
  102. package/dist/features/toast/toastMeta.js +9 -0
  103. package/dist/features/toast/toastMeta.js.map +1 -0
  104. package/dist/features/toast/toastProviderMeta.d.ts +9 -0
  105. package/dist/features/toast/toastProviderMeta.d.ts.map +1 -0
  106. package/dist/features/toast/toastProviderMeta.js +9 -0
  107. package/dist/features/toast/toastProviderMeta.js.map +1 -0
  108. package/dist/index.d.ts +3 -4
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +2 -2
  111. package/dist/index.js.map +1 -1
  112. package/dist/layout/screen/meta.d.ts +1 -1
  113. package/dist/layout/screen-section/meta.d.ts +1 -1
  114. package/dist/metadata/allowedChildren.d.ts +3 -3
  115. package/dist/metadata/allowedChildren.d.ts.map +1 -1
  116. package/dist/metadata/allowedChildren.js +1 -0
  117. package/dist/metadata/allowedChildren.js.map +1 -1
  118. package/dist/metadata/bindableComponentMeta.d.ts +2 -2
  119. package/dist/metadata/componentMeta.d.ts.map +1 -1
  120. package/dist/metadata/componentMeta.js +6 -3
  121. package/dist/metadata/componentMeta.js.map +1 -1
  122. package/dist/patterns/message-bubble/meta.d.ts +1 -1
  123. package/dist/patterns/notice/meta.d.ts +1 -1
  124. package/dist/patterns/panel/meta.d.ts +1 -1
  125. package/dist/patterns/reader/meta.d.ts +2 -2
  126. package/dist/patterns/scanner/meta.d.ts +2 -2
  127. package/dist/patterns/selection/SelectionProvider.d.ts +0 -4
  128. package/dist/patterns/selection/SelectionProvider.d.ts.map +1 -1
  129. package/dist/patterns/selection/SelectionProvider.js +4 -6
  130. package/dist/patterns/selection/SelectionProvider.js.map +1 -1
  131. package/dist/registry.d.ts.map +1 -1
  132. package/dist/registry.js +4 -3
  133. package/dist/registry.js.map +1 -1
  134. package/dist/theme/ZoraProvider.d.ts +4 -10
  135. package/dist/theme/ZoraProvider.d.ts.map +1 -1
  136. package/dist/theme/ZoraProvider.js +8 -6
  137. package/dist/theme/ZoraProvider.js.map +1 -1
  138. package/dist/theme/ZoraRuntimeCapabilities.d.ts +2 -0
  139. package/dist/theme/ZoraRuntimeCapabilities.d.ts.map +1 -0
  140. package/dist/theme/ZoraRuntimeCapabilities.js +2 -0
  141. package/dist/theme/ZoraRuntimeCapabilities.js.map +1 -0
  142. package/dist/theme/ZoraRuntimeCapabilities.native.d.ts +4 -0
  143. package/dist/theme/ZoraRuntimeCapabilities.native.d.ts.map +1 -0
  144. package/dist/theme/ZoraRuntimeCapabilities.native.js +8 -0
  145. package/dist/theme/ZoraRuntimeCapabilities.native.js.map +1 -0
  146. package/dist/theme/ZoraRuntimeCapabilities.web.d.ts +4 -0
  147. package/dist/theme/ZoraRuntimeCapabilities.web.d.ts.map +1 -0
  148. package/dist/theme/ZoraRuntimeCapabilities.web.js +8 -0
  149. package/dist/theme/ZoraRuntimeCapabilities.web.js.map +1 -0
  150. package/dist/theme/ZoraThemeRuntimeContext.d.ts +1 -0
  151. package/dist/theme/ZoraThemeRuntimeContext.d.ts.map +1 -1
  152. package/dist/theme/ZoraThemeRuntimeContext.js +3 -2
  153. package/dist/theme/ZoraThemeRuntimeContext.js.map +1 -1
  154. package/dist/theme/ZoraThemeScope.d.ts +1 -0
  155. package/dist/theme/ZoraThemeScope.d.ts.map +1 -1
  156. package/dist/theme/ZoraThemeScope.js +12 -10
  157. package/dist/theme/ZoraThemeScope.js.map +1 -1
  158. package/dist/theme/index.d.ts +1 -1
  159. package/dist/theme/index.d.ts.map +1 -1
  160. package/dist/theme/index.js.map +1 -1
  161. package/dist/types/accordion.d.ts +23 -0
  162. package/dist/types/accordion.d.ts.map +1 -0
  163. package/dist/types/accordion.js +2 -0
  164. package/dist/types/accordion.js.map +1 -0
  165. package/dist/types/provider.d.ts +19 -0
  166. package/dist/types/provider.d.ts.map +1 -0
  167. package/dist/types/provider.js +2 -0
  168. package/dist/types/provider.js.map +1 -0
  169. package/dist/types/toast.d.ts +9 -0
  170. package/dist/types/toast.d.ts.map +1 -0
  171. package/dist/types/toast.js +2 -0
  172. package/dist/types/toast.js.map +1 -0
  173. package/package.json +2 -2
  174. package/src/features/accordion/accordionItemMeta.ts +46 -0
  175. package/src/features/accordion/accordionMeta.ts +34 -0
  176. package/src/features/accordion/adapters/inbound/Accordion.tsx +94 -0
  177. package/src/features/accordion/adapters/inbound/AccordionItem.tsx +86 -0
  178. package/src/features/accordion/composition/AccordionPresentationContext.ts +6 -0
  179. package/src/features/accordion/public.ts +9 -0
  180. package/src/features/bottom-sheet/public.test.ts +15 -12
  181. package/src/features/date-picker/adapters/inbound/DatePicker.native.tsx +46 -0
  182. package/src/features/date-picker/adapters/inbound/DatePicker.tsx +1 -356
  183. package/src/features/date-picker/adapters/inbound/DatePicker.web.tsx +48 -0
  184. package/src/features/date-picker/composition/DatePickerContent.tsx +256 -0
  185. package/src/features/date-picker/composition/DatePickerField.tsx +53 -0
  186. package/src/features/date-picker/composition/DatePickerTrigger.tsx +47 -0
  187. package/src/features/date-picker/public.test.ts +14 -4
  188. package/src/features/time-picker/adapters/inbound/TimePicker.native.tsx +47 -0
  189. package/src/features/time-picker/adapters/inbound/TimePicker.tsx +1 -258
  190. package/src/features/time-picker/adapters/inbound/TimePicker.web.tsx +49 -0
  191. package/src/features/time-picker/composition/TimePickerContent.tsx +164 -0
  192. package/src/features/time-picker/composition/TimePickerField.tsx +53 -0
  193. package/src/features/time-picker/composition/TimePickerTrigger.tsx +35 -0
  194. package/src/features/time-picker/public.test.ts +14 -3
  195. package/src/features/toast/adapters/inbound/Toast.tsx +13 -0
  196. package/src/features/toast/adapters/inbound/ToastProvider.tsx +9 -0
  197. package/src/features/toast/public.test.ts +19 -0
  198. package/src/features/toast/public.ts +10 -0
  199. package/src/features/toast/toastMeta.ts +10 -0
  200. package/src/features/toast/toastProviderMeta.ts +10 -0
  201. package/src/index.ts +17 -4
  202. package/src/metadata/allowedChildren.ts +1 -0
  203. package/src/metadata/componentMeta.test.ts +9 -0
  204. package/src/metadata/componentMeta.ts +6 -3
  205. package/src/patterns/selection/SelectionProvider.tsx +4 -6
  206. package/src/registry.ts +4 -3
  207. package/src/showcaseCoverage.test.ts +2 -1
  208. package/src/theme/ZoraProvider.tsx +11 -13
  209. package/src/theme/ZoraRuntimeCapabilities.native.tsx +19 -0
  210. package/src/theme/ZoraRuntimeCapabilities.tsx +1 -0
  211. package/src/theme/ZoraRuntimeCapabilities.web.tsx +10 -0
  212. package/src/theme/ZoraThemeRuntimeContext.tsx +3 -2
  213. package/src/theme/ZoraThemeScope.tsx +14 -12
  214. package/src/theme/index.ts +1 -1
  215. package/src/theme/themeConfigScope.test.ts +4 -1
  216. package/src/theme/themeScopeStructure.test.ts +27 -18
  217. package/src/types/accordion.ts +38 -0
  218. package/src/types/provider.ts +22 -0
  219. package/src/{components/toast/types.ts → types/toast.ts} +5 -7
  220. package/dist/components/toast/Toast.d.ts +0 -9
  221. package/dist/components/toast/Toast.d.ts.map +0 -1
  222. package/dist/components/toast/Toast.js +0 -13
  223. package/dist/components/toast/Toast.js.map +0 -1
  224. package/dist/components/toast/ToastProvider.d.ts +0 -9
  225. package/dist/components/toast/ToastProvider.d.ts.map +0 -1
  226. package/dist/components/toast/ToastProvider.js +0 -14
  227. package/dist/components/toast/ToastProvider.js.map +0 -1
  228. package/dist/components/toast/index.d.ts +0 -5
  229. package/dist/components/toast/index.d.ts.map +0 -1
  230. package/dist/components/toast/index.js +0 -4
  231. package/dist/components/toast/index.js.map +0 -1
  232. package/dist/components/toast/meta.d.ts +0 -17
  233. package/dist/components/toast/meta.d.ts.map +0 -1
  234. package/dist/components/toast/meta.js +0 -17
  235. package/dist/components/toast/meta.js.map +0 -1
  236. package/dist/components/toast/types.d.ts +0 -12
  237. package/dist/components/toast/types.d.ts.map +0 -1
  238. package/dist/components/toast/types.js +0 -2
  239. package/dist/components/toast/types.js.map +0 -1
  240. package/dist/patterns/disclosure-section/DisclosureSection.d.ts +0 -9
  241. package/dist/patterns/disclosure-section/DisclosureSection.d.ts.map +0 -1
  242. package/dist/patterns/disclosure-section/DisclosureSection.js +0 -86
  243. package/dist/patterns/disclosure-section/DisclosureSection.js.map +0 -1
  244. package/dist/patterns/disclosure-section/index.d.ts +0 -3
  245. package/dist/patterns/disclosure-section/index.d.ts.map +0 -1
  246. package/dist/patterns/disclosure-section/index.js +0 -3
  247. package/dist/patterns/disclosure-section/index.js.map +0 -1
  248. package/dist/patterns/disclosure-section/meta.d.ts +0 -9
  249. package/dist/patterns/disclosure-section/meta.d.ts.map +0 -1
  250. package/dist/patterns/disclosure-section/meta.js +0 -9
  251. package/dist/patterns/disclosure-section/meta.js.map +0 -1
  252. package/dist/patterns/disclosure-section/types.d.ts +0 -15
  253. package/dist/patterns/disclosure-section/types.d.ts.map +0 -1
  254. package/dist/patterns/disclosure-section/types.js +0 -2
  255. package/dist/patterns/disclosure-section/types.js.map +0 -1
  256. package/src/components/toast/Toast.tsx +0 -16
  257. package/src/components/toast/ToastProvider.tsx +0 -17
  258. package/src/components/toast/index.ts +0 -4
  259. package/src/components/toast/meta.ts +0 -19
  260. package/src/patterns/disclosure-section/DisclosureSection.tsx +0 -130
  261. package/src/patterns/disclosure-section/index.ts +0 -2
  262. package/src/patterns/disclosure-section/meta.ts +0 -10
  263. package/src/patterns/disclosure-section/types.ts +0 -16
@@ -0,0 +1,53 @@
1
+ import { Field } from '@ankhorage/surface';
2
+ import type React from 'react';
3
+
4
+ import type { TimePickerProps } from '../../../types/time-picker';
5
+ import { Stack } from '../../layout/public';
6
+ import { Text } from '../../typography/public';
7
+
8
+ /*** Renders the shared TimePicker field frame around a platform-specific trigger. */
9
+ export function TimePickerField({
10
+ children,
11
+ description,
12
+ disabled,
13
+ error,
14
+ label,
15
+ required,
16
+ testID,
17
+ }: TimePickerFieldProps) {
18
+ return (
19
+ <Field
20
+ disabled={disabled}
21
+ errorText={error}
22
+ invalid={Boolean(error)}
23
+ label={label ? renderLabel(label, description) : undefined}
24
+ required={required}
25
+ testID={testID}
26
+ >
27
+ {children}
28
+ </Field>
29
+ );
30
+ }
31
+
32
+ interface TimePickerFieldProps extends Pick<
33
+ TimePickerProps,
34
+ 'description' | 'disabled' | 'error' | 'label' | 'required' | 'testID'
35
+ > {
36
+ children: React.ReactNode;
37
+ }
38
+
39
+ /*** Renders the picker label and optional supporting description. */
40
+ function renderLabel(label: React.ReactNode, description: React.ReactNode | undefined) {
41
+ return (
42
+ <Stack gap="xs">
43
+ <Text variant="label" weight="semiBold">
44
+ {label}
45
+ </Text>
46
+ {description ? (
47
+ <Text emphasis="muted" variant="bodySmall">
48
+ {description}
49
+ </Text>
50
+ ) : null}
51
+ </Stack>
52
+ );
53
+ }
@@ -0,0 +1,35 @@
1
+ import type { TimePickerProps } from '../../../types/time-picker';
2
+ import { Button } from '../../button/public';
3
+
4
+ /*** Renders the shared TimePicker trigger button for native and web hosts. */
5
+ export function TimePickerTrigger({
6
+ disabled,
7
+ formatTime,
8
+ interactionPolicy,
9
+ onPress,
10
+ placeholder = 'Choose time',
11
+ testID,
12
+ value,
13
+ }: TimePickerTriggerProps) {
14
+ const displayValue = value ? (formatTime ? formatTime(value) : value) : placeholder;
15
+
16
+ return (
17
+ <Button
18
+ disabled={disabled}
19
+ interactionPolicy={interactionPolicy}
20
+ onPress={onPress}
21
+ testID={testID ? `${testID}-trigger` : undefined}
22
+ trailingIcon={{ name: 'chevron-down-outline' }}
23
+ variant="outline"
24
+ >
25
+ {displayValue}
26
+ </Button>
27
+ );
28
+ }
29
+
30
+ interface TimePickerTriggerProps extends Pick<
31
+ TimePickerProps,
32
+ 'disabled' | 'formatTime' | 'interactionPolicy' | 'placeholder' | 'testID' | 'value'
33
+ > {
34
+ onPress: () => void;
35
+ }
@@ -2,13 +2,24 @@ import { expect, test } from 'bun:test';
2
2
 
3
3
  import { ZORA_COMPONENT_META } from '../../metadata/componentMeta';
4
4
 
5
- test('TimePicker exposes a serializable manifest contract through the shared BottomSheet', async () => {
6
- const source = await Bun.file('src/features/time-picker/adapters/inbound/TimePicker.tsx').text();
5
+ test('TimePicker keeps one manifest contract across native and web presentation hosts', async () => {
6
+ const nativeSource = await Bun.file(
7
+ 'src/features/time-picker/adapters/inbound/TimePicker.native.tsx',
8
+ ).text();
9
+ const webSource = await Bun.file(
10
+ 'src/features/time-picker/adapters/inbound/TimePicker.web.tsx',
11
+ ).text();
12
+ const contentSource = await Bun.file(
13
+ 'src/features/time-picker/composition/TimePickerContent.tsx',
14
+ ).text();
7
15
  const meta = ZORA_COMPONENT_META.TimePicker;
8
16
 
9
17
  expect(meta.directManifestNode).toBe(true);
10
18
  expect(meta.props.value?.type).toBe('string');
11
19
  expect(meta.events?.valueChange?.eventType).toBe('timePicker.valueChange');
12
20
  expect(meta.bindings?.props?.value?.value.type).toBe('string');
13
- expect(source).toContain('useBottomSheet()');
21
+ expect(nativeSource).toContain('useBottomSheet()');
22
+ expect(webSource).toContain('<Popover');
23
+ expect(webSource).not.toContain('useBottomSheet');
24
+ expect(contentSource).toContain('TimePickerOption');
14
25
  });
@@ -0,0 +1,13 @@
1
+ import { Toast as SurfaceToast } from '@ankhorage/surface';
2
+ import React from 'react';
3
+
4
+ import { withZoraThemeScope } from '../../../../theme/withZoraThemeScope';
5
+ import type { ToastProps } from '../../../../types/toast';
6
+
7
+ /*** Renders a toast notification message with ZORA theme scoping. */
8
+ export const Toast = withZoraThemeScope(ToastInner);
9
+
10
+ /*** Applies the ZORA theme scope before delegating toast presentation to Surface. */
11
+ function ToastInner({ mode: _mode, themeId: _themeId, ...props }: ToastProps) {
12
+ return <SurfaceToast {...props} />;
13
+ }
@@ -0,0 +1,9 @@
1
+ import { ToastProvider as SurfaceToastProvider } from '@ankhorage/surface';
2
+ import React from 'react';
3
+
4
+ import type { ToastProviderProps } from '../../../../types/toast';
5
+
6
+ /*** Provides toast state and rendering context through the Surface runtime host. */
7
+ export function ToastProvider(props: ToastProviderProps) {
8
+ return <SurfaceToastProvider {...props} />;
9
+ }
@@ -0,0 +1,19 @@
1
+ import { expect, test } from 'bun:test';
2
+
3
+ import { ZORA_COMPONENT_META } from '../../metadata/componentMeta';
4
+
5
+ test('Toast stays imperative and installs its host only when the ZoraProvider capability is enabled', async () => {
6
+ const [publicSource, providerSource, webCapabilities, nativeCapabilities] = await Promise.all([
7
+ Bun.file('src/features/toast/public.ts').text(),
8
+ Bun.file('src/theme/ZoraProvider.tsx').text(),
9
+ Bun.file('src/theme/ZoraRuntimeCapabilities.web.tsx').text(),
10
+ Bun.file('src/theme/ZoraRuntimeCapabilities.native.tsx').text(),
11
+ ]);
12
+
13
+ expect(ZORA_COMPONENT_META.Toast?.directManifestNode).toBe(false);
14
+ expect(ZORA_COMPONENT_META.ToastProvider?.directManifestNode).toBe(false);
15
+ expect(publicSource).toContain("useToast } from '@ankhorage/surface'");
16
+ expect(providerSource).toContain('toast = false');
17
+ expect(webCapabilities).toContain('if (!toast)');
18
+ expect(nativeCapabilities).toContain('toast ?');
19
+ });
@@ -0,0 +1,10 @@
1
+ export type {
2
+ ToastController,
3
+ ToastOptions,
4
+ ToastProps,
5
+ ToastProviderProps,
6
+ ToastStatus,
7
+ } from '../../types/toast';
8
+ export { Toast } from './adapters/inbound/Toast';
9
+ export { ToastProvider } from './adapters/inbound/ToastProvider';
10
+ export { useToast } from '@ankhorage/surface';
@@ -0,0 +1,10 @@
1
+ import type { ZoraComponentMeta } from '../../metadata';
2
+
3
+ export const toastMeta = {
4
+ name: 'Toast',
5
+ category: 'component',
6
+ directManifestNode: false,
7
+ allowedChildren: [],
8
+ note: 'Transient feedback component exposed through the imperative toast workflow, not as a manifest node.',
9
+ props: {},
10
+ } as const satisfies ZoraComponentMeta;
@@ -0,0 +1,10 @@
1
+ import type { ZoraComponentMeta } from '../../metadata';
2
+
3
+ export const toastProviderMeta = {
4
+ name: 'ToastProvider',
5
+ category: 'component',
6
+ directManifestNode: false,
7
+ allowedChildren: [],
8
+ note: 'Provider for imperative toast feedback; application roots should normally enable the ZoraProvider toast capability.',
9
+ props: {},
10
+ } as const satisfies ZoraComponentMeta;
package/src/index.ts CHANGED
@@ -16,12 +16,19 @@ export type { SelectOption, SelectProps } from './components/select';
16
16
  export { Select } from './components/select';
17
17
  export type { TabItem, TabsProps, TabsVariant } from './components/tabs';
18
18
  export { Tabs } from './components/tabs';
19
- export type { ToastOptions, ToastProps, ToastProviderProps, ToastStatus } from './components/toast';
20
- export { Toast, ToastProvider, useToast } from './components/toast';
21
19
  export type { ToolbarActionProps, ToolbarPosition, ToolbarProps } from './components/toolbar';
22
20
  export { Toolbar, ToolbarAction } from './components/toolbar';
23
21
  export { ZORA_CORE_PLUGIN } from './corePlugin';
24
22
  export { ZORA_CORE_PLUGIN_METADATA } from './corePluginMetadata';
23
+ export {
24
+ Accordion,
25
+ AccordionItem,
26
+ type AccordionItemProps,
27
+ type AccordionMode,
28
+ type AccordionMultipleProps,
29
+ type AccordionProps,
30
+ type AccordionSingleProps,
31
+ } from './features/accordion/public';
25
32
  export {
26
33
  ActivityIndicator,
27
34
  type ActivityIndicatorProps,
@@ -238,6 +245,14 @@ export {
238
245
  type TimePickerProps,
239
246
  type TimePickerValue,
240
247
  } from './features/time-picker/public';
248
+ export type {
249
+ ToastController,
250
+ ToastOptions,
251
+ ToastProps,
252
+ ToastProviderProps,
253
+ ToastStatus,
254
+ } from './features/toast/public';
255
+ export { Toast, ToastProvider, useToast } from './features/toast/public';
241
256
  export type {
242
257
  HeadingAlign,
243
258
  HeadingColor,
@@ -334,8 +349,6 @@ export type {
334
349
  export { CollectionEditor } from './patterns/collection-editor';
335
350
  export type { ConfirmDialogProps } from './patterns/confirm-dialog';
336
351
  export { ConfirmDialog } from './patterns/confirm-dialog';
337
- export type { DisclosureSectionProps } from './patterns/disclosure-section';
338
- export { DisclosureSection } from './patterns/disclosure-section';
339
352
  export type { FilterBarProps } from './patterns/filter-bar';
340
353
  export { FilterBar } from './patterns/filter-bar';
341
354
  export type { InspectorFieldProps } from './patterns/inspector-field';
@@ -6,6 +6,7 @@ export const CONTAINER_ALLOWED_CHILDREN = [
6
6
  'OtpForm',
7
7
  'SignInForm',
8
8
  'SignUpForm',
9
+ 'Accordion',
9
10
  'Surface',
10
11
  'Avatar',
11
12
  'AvatarGroup',
@@ -186,6 +186,8 @@ describe('ZORA_COMPONENT_META invariants', () => {
186
186
  ]);
187
187
 
188
188
  const expectedContainerNodes = new Set([
189
+ 'Accordion',
190
+ 'AccordionItem',
189
191
  'Form',
190
192
  'Gradient',
191
193
  'Surface',
@@ -234,6 +236,13 @@ describe('ZORA_COMPONENT_META invariants', () => {
234
236
  }
235
237
  });
236
238
 
239
+ test('Accordion constrains authored items to its canonical hierarchy', () => {
240
+ expect(ZORA_COMPONENT_META.Accordion.directManifestNode).toBe(true);
241
+ expect(ZORA_COMPONENT_META.Accordion.allowedChildren).toEqual(['AccordionItem']);
242
+ expect(ZORA_COMPONENT_META.AccordionItem.directManifestNode).toBe(true);
243
+ expect(ZORA_COMPONENT_META.AccordionItem.allowedChildren).not.toContain('AccordionItem');
244
+ });
245
+
237
246
  test('Image is a direct manifest leaf with canonical media authoring metadata', () => {
238
247
  expect(ZORA_COMPONENT_META.Image.directManifestNode).toBe(true);
239
248
  expect(ZORA_COMPONENT_META.Image.allowedChildren).toEqual([]);
@@ -7,8 +7,9 @@ import { ratingMeta } from '../components/rating/meta';
7
7
  import { searchBarMeta } from '../components/search-bar/meta';
8
8
  import { selectMeta } from '../components/select/meta';
9
9
  import { tabsMeta } from '../components/tabs/meta';
10
- import { toastMeta, toastProviderMeta } from '../components/toast/meta';
11
10
  import { toolbarActionMeta, toolbarMeta } from '../components/toolbar/meta';
11
+ import { accordionItemMeta } from '../features/accordion/accordionItemMeta';
12
+ import { accordionMeta } from '../features/accordion/accordionMeta';
12
13
  import { activityIndicatorMeta } from '../features/activity-indicator/activityIndicatorMeta';
13
14
  import { forgotPasswordFormMeta } from '../features/auth/forgotPasswordFormMeta';
14
15
  import { oauthProviderButtonMeta } from '../features/auth/oauthProviderButtonMeta';
@@ -63,6 +64,8 @@ import {
63
64
  } from '../features/skeleton/skeletonMeta';
64
65
  import { surfaceMeta } from '../features/surface/surfaceMeta';
65
66
  import { timePickerMeta } from '../features/time-picker/timePickerMeta';
67
+ import { toastMeta } from '../features/toast/toastMeta';
68
+ import { toastProviderMeta } from '../features/toast/toastProviderMeta';
66
69
  import { headingMeta } from '../features/typography/headingMeta';
67
70
  import { textMeta } from '../features/typography/textMeta';
68
71
  import { uploaderMeta } from '../features/uploader/uploaderMeta';
@@ -76,7 +79,6 @@ import { topbarLayoutMeta } from '../layout/topbar-layout/meta';
76
79
  import { chatListItemMeta } from '../patterns/chat-list-item/meta';
77
80
  import { collectionEditorMeta } from '../patterns/collection-editor/meta';
78
81
  import { confirmDialogMeta } from '../patterns/confirm-dialog/meta';
79
- import { disclosureSectionMeta } from '../patterns/disclosure-section/meta';
80
82
  import { filterBarMeta } from '../patterns/filter-bar/meta';
81
83
  import { inspectorFieldMeta } from '../patterns/inspector-field/meta';
82
84
  import { listMeta, listRowMeta, listSectionMeta } from '../patterns/list/meta';
@@ -103,6 +105,8 @@ import type { ZoraComponentMetaRegistry } from './types';
103
105
 
104
106
  export const ZORA_COMPONENT_META: ZoraComponentMetaRegistry = finalizeFeatureMetadata({
105
107
  ...foundationMetas,
108
+ Accordion: accordionMeta,
109
+ AccordionItem: accordionItemMeta,
106
110
  ActivityIndicator: activityIndicatorMeta,
107
111
  Box: boxMeta,
108
112
  Container: containerMeta,
@@ -180,7 +184,6 @@ export const ZORA_COMPONENT_META: ZoraComponentMetaRegistry = finalizeFeatureMet
180
184
  CollectionEditor: collectionEditorMeta,
181
185
  ConfirmDialog: confirmDialogMeta,
182
186
  ContentRail: contentRailMeta,
183
- DisclosureSection: disclosureSectionMeta,
184
187
  EmptyState: emptyStateMeta,
185
188
  FilterBar: filterBarMeta,
186
189
  Hero: heroMeta,
@@ -10,21 +10,21 @@ type SelectionContextValue = UseSelectionResult;
10
10
 
11
11
  const SelectionContext = React.createContext<SelectionContextValue | null>(null);
12
12
 
13
+ /*** Resolve the effective selection mode. */
13
14
  function resolveMode(mode: SelectionMode | undefined): SelectionMode {
14
15
  return mode ?? 'single';
15
16
  }
16
17
 
18
+ /*** Resolve the effective disabled state. */
17
19
  function resolveDisabled(disabled: boolean | undefined): boolean {
18
20
  return disabled ?? false;
19
21
  }
20
22
 
21
23
  /***
22
24
  * Accesses selection state provided by `SelectionProvider`.
23
- *
24
-
25
25
  */
26
26
  export function useSelection(): UseSelectionResult {
27
- const value = React.useContext(SelectionContext);
27
+ const value = React.use(SelectionContext);
28
28
  if (!value) {
29
29
  throw new Error(MISSING_CONTEXT_MESSAGE);
30
30
  }
@@ -34,8 +34,6 @@ export function useSelection(): UseSelectionResult {
34
34
 
35
35
  /***
36
36
  * Provides selection state for building selectable lists and grids.
37
- *
38
-
39
37
  */
40
38
  export function SelectionProvider({
41
39
  children,
@@ -110,5 +108,5 @@ export function SelectionProvider({
110
108
  };
111
109
  }, [clear, currentNormalizedIds, resolvedDisabled, resolvedMode, select, selectedIdSet, toggle]);
112
110
 
113
- return <SelectionContext.Provider value={value}>{children}</SelectionContext.Provider>;
111
+ return <SelectionContext value={value}>{children}</SelectionContext>;
114
112
  }
package/src/registry.ts CHANGED
@@ -10,8 +10,8 @@ import { Rating } from './components/rating';
10
10
  import { SearchBar } from './components/search-bar';
11
11
  import { Select } from './components/select';
12
12
  import { Tabs } from './components/tabs';
13
- import { Toast } from './components/toast';
14
13
  import { Toolbar, ToolbarAction } from './components/toolbar';
14
+ import { Accordion, AccordionItem } from './features/accordion/public';
15
15
  import { ActivityIndicator } from './features/activity-indicator/public';
16
16
  import {
17
17
  ForgotPasswordForm,
@@ -55,6 +55,7 @@ import { Progress, ProgressRing } from './features/progress/public';
55
55
  import { Skeleton, SkeletonCard, SkeletonList, SkeletonText } from './features/skeleton/public';
56
56
  import { Surface } from './features/surface/public';
57
57
  import { TimePicker } from './features/time-picker/public';
58
+ import { Toast } from './features/toast/public';
58
59
  import { Heading } from './features/typography/public';
59
60
  import { Text } from './features/typography/public';
60
61
  import { Uploader } from './features/uploader/public';
@@ -68,7 +69,6 @@ import { TopbarLayout } from './layout/topbar-layout';
68
69
  import { ChatListItem } from './patterns/chat-list-item';
69
70
  import { CollectionEditor } from './patterns/collection-editor';
70
71
  import { ConfirmDialog } from './patterns/confirm-dialog';
71
- import { DisclosureSection } from './patterns/disclosure-section';
72
72
  import { FilterBar } from './patterns/filter-bar';
73
73
  import { InspectorField } from './patterns/inspector-field';
74
74
  import { List, ListRow, ListSection } from './patterns/list';
@@ -113,6 +113,8 @@ type _RegistryInteractionPolicyCheck = _AssertTrue<
113
113
  >;
114
114
 
115
115
  const _ZORA_COMPONENT_REGISTRY = {
116
+ Accordion,
117
+ AccordionItem,
116
118
  ActivityIndicator,
117
119
  AppBar,
118
120
  Avatar,
@@ -193,7 +195,6 @@ const _ZORA_COMPONENT_REGISTRY = {
193
195
  CollectionEditor,
194
196
  ConfirmDialog,
195
197
  ContentRail,
196
- DisclosureSection,
197
198
  EmptyState,
198
199
  FilterBar,
199
200
  Hero,
@@ -17,6 +17,8 @@ const IGNORED_DIRECTORY_NAMES = new Set([
17
17
 
18
18
  const REQUIRED_SHOWCASE_COVERAGE = {
19
19
  components: [
20
+ 'Accordion',
21
+ 'AccordionItem',
20
22
  'AppBar',
21
23
  'Avatar',
22
24
  'AvatarGroup',
@@ -81,7 +83,6 @@ const REQUIRED_SHOWCASE_COVERAGE = {
81
83
  'SignUpForm',
82
84
  'CollectionEditor',
83
85
  'ConfirmDialog',
84
- 'DisclosureSection',
85
86
  'EmptyState',
86
87
  'FilterBar',
87
88
  'SelectableItem',
@@ -1,26 +1,22 @@
1
- import type { ThemeConfig } from '@ankhorage/contracts';
2
1
  import { ThemeProvider } from '@ankhorage/surface';
3
- import { BottomSheetProvider } from '@ankhorage/surface/bottom-sheet';
4
2
  import React from 'react';
5
3
 
4
+ import type { ZoraProviderProps } from '../types/provider';
6
5
  import { createZoraThemeConfig } from './createZoraThemeConfig';
7
- import type { ZoraTheme, ZoraThemeMode } from './types';
8
6
  import { zoraDefaultTheme } from './zoraDefaultTheme';
7
+ import { ZoraRuntimeCapabilities } from './ZoraRuntimeCapabilities';
9
8
  import { ZoraThemeRuntimeContext } from './ZoraThemeRuntimeContext';
10
9
 
11
- export interface ZoraProviderProps {
12
- children: React.ReactNode;
13
- theme?: ZoraTheme;
14
- themeConfig?: ThemeConfig;
15
- initialMode?: ZoraThemeMode;
16
- }
10
+ export type { ZoraProviderProps, ZoraToastCapability } from '../types/provider';
17
11
 
18
- /** Installs the ZORA theme runtime, Surface theme, and shared bottom-sheet controller. */
12
+ /*** Installs the core ZORA theme runtime and explicitly enabled optional capabilities. */
19
13
  export function ZoraProvider({
14
+ bottomSheet = false,
20
15
  children,
21
16
  theme = zoraDefaultTheme,
22
17
  themeConfig,
23
18
  initialMode = 'light',
19
+ toast = false,
24
20
  }: ZoraProviderProps) {
25
21
  const resolvedConfig = React.useMemo(
26
22
  () => themeConfig ?? createZoraThemeConfig(theme),
@@ -29,10 +25,12 @@ export function ZoraProvider({
29
25
  const runtimeValue = React.useMemo(() => ({ themeId: resolvedConfig.id }), [resolvedConfig.id]);
30
26
 
31
27
  return (
32
- <ZoraThemeRuntimeContext.Provider value={runtimeValue}>
28
+ <ZoraThemeRuntimeContext value={runtimeValue}>
33
29
  <ThemeProvider initialConfig={resolvedConfig} initialMode={initialMode}>
34
- <BottomSheetProvider>{children}</BottomSheetProvider>
30
+ <ZoraRuntimeCapabilities bottomSheet={bottomSheet} toast={toast}>
31
+ {children}
32
+ </ZoraRuntimeCapabilities>
35
33
  </ThemeProvider>
36
- </ZoraThemeRuntimeContext.Provider>
34
+ </ZoraThemeRuntimeContext>
37
35
  );
38
36
  }
@@ -0,0 +1,19 @@
1
+ import { ToastProvider as SurfaceToastProvider } from '@ankhorage/surface';
2
+ import { BottomSheetProvider } from '@ankhorage/surface/bottom-sheet';
3
+
4
+ import type { ZoraRuntimeCapabilitiesProps } from '../types/provider';
5
+
6
+ /*** Installs optional native runtime capabilities without forcing unused hosts. */
7
+ export function ZoraRuntimeCapabilities({
8
+ bottomSheet,
9
+ children,
10
+ toast,
11
+ }: ZoraRuntimeCapabilitiesProps) {
12
+ const toastContent = toast ? (
13
+ <SurfaceToastProvider {...(toast === true ? {} : toast)}>{children}</SurfaceToastProvider>
14
+ ) : (
15
+ children
16
+ );
17
+
18
+ return bottomSheet ? <BottomSheetProvider>{toastContent}</BottomSheetProvider> : toastContent;
19
+ }
@@ -0,0 +1 @@
1
+ export { ZoraRuntimeCapabilities } from './ZoraRuntimeCapabilities.web';
@@ -0,0 +1,10 @@
1
+ import { ToastProvider as SurfaceToastProvider } from '@ankhorage/surface';
2
+
3
+ import type { ZoraRuntimeCapabilitiesProps } from '../types/provider';
4
+
5
+ /*** Installs only web-relevant optional runtime capabilities. */
6
+ export function ZoraRuntimeCapabilities({ children, toast }: ZoraRuntimeCapabilitiesProps) {
7
+ if (!toast) return children;
8
+
9
+ return <SurfaceToastProvider {...(toast === true ? {} : toast)}>{children}</SurfaceToastProvider>;
10
+ }
@@ -1,4 +1,4 @@
1
- import { createContext, useContext } from 'react';
1
+ import { createContext, use } from 'react';
2
2
 
3
3
  import type { ZoraThemeId } from './types';
4
4
  import { zoraDefaultTheme } from './zoraDefaultTheme';
@@ -11,6 +11,7 @@ export const ZoraThemeRuntimeContext = createContext<ZoraThemeRuntime>({
11
11
  themeId: zoraDefaultTheme.id,
12
12
  });
13
13
 
14
+ /*** Returns the active ZORA theme runtime. */
14
15
  export function useZoraThemeRuntime(): ZoraThemeRuntime {
15
- return useContext(ZoraThemeRuntimeContext);
16
+ return use(ZoraThemeRuntimeContext);
16
17
  }
@@ -11,6 +11,17 @@ export interface ZoraThemeScopeProps {
11
11
  mode?: ZoraThemeMode;
12
12
  }
13
13
 
14
+ /*** Applies nested ZORA theme overrides without installing another Surface theme runtime. */
15
+ export function ZoraThemeScope({ children, themeId, mode }: ZoraThemeScopeProps) {
16
+ if (mode === undefined && themeId === undefined) return children;
17
+ return (
18
+ <ZoraThemeScopeInner mode={mode} themeId={themeId}>
19
+ {children}
20
+ </ZoraThemeScopeInner>
21
+ );
22
+ }
23
+
24
+ /*** Resolves and provides the scoped Surface and ZORA theme runtime values. */
14
25
  function ZoraThemeScopeInner({ children, themeId, mode }: ZoraThemeScopeProps) {
15
26
  const parentSurface = useTheme();
16
27
  const parentRuntime = useZoraThemeRuntime();
@@ -38,17 +49,8 @@ function ZoraThemeScopeInner({ children, themeId, mode }: ZoraThemeScopeProps) {
38
49
  const scopedRuntimeValue = useMemo(() => ({ themeId: scopedThemeId }), [scopedThemeId]);
39
50
 
40
51
  return (
41
- <ZoraThemeRuntimeContext.Provider value={scopedRuntimeValue}>
42
- <ThemeContext.Provider value={scopedSurfaceValue}>{children}</ThemeContext.Provider>
43
- </ZoraThemeRuntimeContext.Provider>
44
- );
45
- }
46
-
47
- export function ZoraThemeScope({ children, themeId, mode }: ZoraThemeScopeProps) {
48
- if (mode === undefined && themeId === undefined) return children;
49
- return (
50
- <ZoraThemeScopeInner mode={mode} themeId={themeId}>
51
- {children}
52
- </ZoraThemeScopeInner>
52
+ <ZoraThemeRuntimeContext value={scopedRuntimeValue}>
53
+ <ThemeContext value={scopedSurfaceValue}>{children}</ThemeContext>
54
+ </ZoraThemeRuntimeContext>
53
55
  );
54
56
  }
@@ -4,7 +4,7 @@ export type { ThemeModeToggleProps } from './ThemeModeToggleProps';
4
4
  export { useZoraTheme } from './useZoraTheme';
5
5
  export { withZoraThemeScope } from './withZoraThemeScope';
6
6
  export type { ZoraBaseProps } from './ZoraBaseProps';
7
- export type { ZoraProviderProps } from './ZoraProvider';
7
+ export type { ZoraProviderProps, ZoraToastCapability } from './ZoraProvider';
8
8
  export { ZoraProvider } from './ZoraProvider';
9
9
  export type { ZoraThemeScopeProps } from './ZoraThemeScope';
10
10
  export { ZoraThemeScope } from './ZoraThemeScope';
@@ -4,12 +4,15 @@ import { join } from 'node:path';
4
4
  import { describe, expect, test } from 'bun:test';
5
5
 
6
6
  const themeDir = import.meta.dir;
7
+ const srcDir = join(themeDir, '..');
7
8
 
8
9
  describe('canonical ThemeConfig scope propagation', () => {
9
10
  test('provider accepts the canonical ThemeConfig without duplicating live config state', () => {
10
11
  const provider = readFileSync(join(themeDir, 'ZoraProvider.tsx'), 'utf8');
12
+ const providerTypes = readFileSync(join(srcDir, 'types', 'provider.ts'), 'utf8');
11
13
  const context = readFileSync(join(themeDir, 'ZoraThemeRuntimeContext.tsx'), 'utf8');
12
- expect(provider).toContain('themeConfig?: ThemeConfig');
14
+
15
+ expect(providerTypes).toContain('themeConfig?: ThemeConfig');
13
16
  expect(provider).toContain('themeConfig ?? createZoraThemeConfig(theme)');
14
17
  expect(context).not.toContain('ThemeConfig');
15
18
  expect(context).not.toContain('sourceTheme');