@ankhorage/zora 11.0.0 → 12.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 (252) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +2 -1
  3. package/dist/constants.d.ts +3 -0
  4. package/dist/constants.d.ts.map +1 -1
  5. package/dist/constants.js +3 -0
  6. package/dist/constants.js.map +1 -1
  7. package/dist/features/bottom-sheet/bottomSheetMeta.d.ts +1 -1
  8. package/dist/features/card/cardMeta.d.ts +1 -1
  9. package/dist/features/card/mediaCardMeta.d.ts +1 -1
  10. package/dist/features/card/postCardMeta.d.ts +1 -1
  11. package/dist/features/data-table/adapters/inbound/DataTable.d.ts.map +1 -1
  12. package/dist/features/data-table/adapters/inbound/DataTable.js +1 -1
  13. package/dist/features/data-table/adapters/inbound/DataTable.js.map +1 -1
  14. package/dist/{components/date-picker → features/date-picker/adapters/inbound}/DatePicker.d.ts +1 -1
  15. package/dist/features/date-picker/adapters/inbound/DatePicker.d.ts.map +1 -0
  16. package/dist/{components/date-picker → features/date-picker/adapters/inbound}/DatePicker.js +23 -26
  17. package/dist/features/date-picker/adapters/inbound/DatePicker.js.map +1 -0
  18. package/dist/features/date-picker/datePickerMeta.d.ts +83 -0
  19. package/dist/features/date-picker/datePickerMeta.d.ts.map +1 -0
  20. package/dist/features/date-picker/datePickerMeta.js +57 -0
  21. package/dist/features/date-picker/datePickerMeta.js.map +1 -0
  22. package/dist/features/date-picker/public.d.ts +3 -0
  23. package/dist/features/date-picker/public.d.ts.map +1 -0
  24. package/dist/features/date-picker/public.js +2 -0
  25. package/dist/features/date-picker/public.js.map +1 -0
  26. package/dist/features/date-picker/utils/localDate.d.ts +5 -0
  27. package/dist/features/date-picker/utils/localDate.d.ts.map +1 -0
  28. package/dist/features/date-picker/utils/localDate.js +27 -0
  29. package/dist/features/date-picker/utils/localDate.js.map +1 -0
  30. package/dist/{patterns/hero → features/hero/adapters/inbound}/Hero.d.ts +1 -1
  31. package/dist/features/hero/adapters/inbound/Hero.d.ts.map +1 -0
  32. package/dist/{patterns/hero → features/hero/adapters/inbound}/Hero.js +5 -6
  33. package/dist/features/hero/adapters/inbound/Hero.js.map +1 -0
  34. package/dist/{patterns/hero/meta.d.ts → features/hero/heroMeta.d.ts} +1 -1
  35. package/dist/features/hero/heroMeta.d.ts.map +1 -0
  36. package/dist/{patterns/hero/meta.js → features/hero/heroMeta.js} +1 -1
  37. package/dist/features/hero/heroMeta.js.map +1 -0
  38. package/dist/features/hero/public.d.ts +3 -0
  39. package/dist/features/hero/public.d.ts.map +1 -0
  40. package/dist/features/hero/public.js +2 -0
  41. package/dist/features/hero/public.js.map +1 -0
  42. package/dist/features/keyboard-avoiding-view/keyboardAvoidingViewMeta.d.ts +1 -1
  43. package/dist/features/layout/boxMeta.d.ts +1 -1
  44. package/dist/features/layout/containerMeta.d.ts +1 -1
  45. package/dist/features/layout/gridMeta.d.ts +1 -1
  46. package/dist/features/layout/stackMeta.d.ts +1 -1
  47. package/dist/features/list/flatListMeta.d.ts +1 -1
  48. package/dist/features/list/sectionListMeta.d.ts +1 -1
  49. package/dist/{patterns/missing-element → features/missing-element/adapters/inbound}/MissingElement.d.ts +1 -1
  50. package/dist/features/missing-element/adapters/inbound/MissingElement.d.ts.map +1 -0
  51. package/dist/{patterns/missing-element → features/missing-element/adapters/inbound}/MissingElement.js +5 -5
  52. package/dist/features/missing-element/adapters/inbound/MissingElement.js.map +1 -0
  53. package/dist/{patterns/missing-element/meta.d.ts → features/missing-element/missingElementMeta.d.ts} +1 -1
  54. package/dist/features/missing-element/missingElementMeta.d.ts.map +1 -0
  55. package/dist/{patterns/missing-element/meta.js → features/missing-element/missingElementMeta.js} +1 -1
  56. package/dist/features/missing-element/missingElementMeta.js.map +1 -0
  57. package/dist/features/missing-element/public.d.ts +3 -0
  58. package/dist/features/missing-element/public.d.ts.map +1 -0
  59. package/dist/features/missing-element/public.js +2 -0
  60. package/dist/features/missing-element/public.js.map +1 -0
  61. package/dist/{components/skeleton → features/skeleton/adapters/inbound}/Skeleton.d.ts +1 -1
  62. package/dist/features/skeleton/adapters/inbound/Skeleton.d.ts.map +1 -0
  63. package/dist/{components/skeleton → features/skeleton/adapters/inbound}/Skeleton.js +3 -3
  64. package/dist/features/skeleton/adapters/inbound/Skeleton.js.map +1 -0
  65. package/dist/{components/skeleton → features/skeleton/adapters/inbound}/SkeletonCard.d.ts +1 -1
  66. package/dist/features/skeleton/adapters/inbound/SkeletonCard.d.ts.map +1 -0
  67. package/dist/{components/skeleton → features/skeleton/adapters/inbound}/SkeletonCard.js +4 -4
  68. package/dist/features/skeleton/adapters/inbound/SkeletonCard.js.map +1 -0
  69. package/dist/{components/skeleton → features/skeleton/adapters/inbound}/SkeletonList.d.ts +1 -1
  70. package/dist/features/skeleton/adapters/inbound/SkeletonList.d.ts.map +1 -0
  71. package/dist/{components/skeleton → features/skeleton/adapters/inbound}/SkeletonList.js +2 -2
  72. package/dist/features/skeleton/adapters/inbound/SkeletonList.js.map +1 -0
  73. package/dist/{components/skeleton → features/skeleton/adapters/inbound}/SkeletonText.d.ts +1 -1
  74. package/dist/features/skeleton/adapters/inbound/SkeletonText.d.ts.map +1 -0
  75. package/dist/{components/skeleton → features/skeleton/adapters/inbound}/SkeletonText.js +2 -2
  76. package/dist/features/skeleton/adapters/inbound/SkeletonText.js.map +1 -0
  77. package/dist/features/skeleton/public.d.ts +6 -0
  78. package/dist/features/skeleton/public.d.ts.map +1 -0
  79. package/dist/features/skeleton/public.js +5 -0
  80. package/dist/features/skeleton/public.js.map +1 -0
  81. package/dist/features/skeleton/skeletonMeta.d.ts +178 -0
  82. package/dist/features/skeleton/skeletonMeta.d.ts.map +1 -0
  83. package/dist/features/skeleton/skeletonMeta.js +84 -0
  84. package/dist/features/skeleton/skeletonMeta.js.map +1 -0
  85. package/dist/features/surface/surfaceMeta.d.ts +1 -1
  86. package/dist/{components/time-picker → features/time-picker/adapters/inbound}/TimePicker.d.ts +1 -1
  87. package/dist/features/time-picker/adapters/inbound/TimePicker.d.ts.map +1 -0
  88. package/dist/{components/time-picker → features/time-picker/adapters/inbound}/TimePicker.js +8 -11
  89. package/dist/features/time-picker/adapters/inbound/TimePicker.js.map +1 -0
  90. package/dist/features/time-picker/public.d.ts +3 -0
  91. package/dist/features/time-picker/public.d.ts.map +1 -0
  92. package/dist/features/time-picker/public.js +2 -0
  93. package/dist/features/time-picker/public.js.map +1 -0
  94. package/dist/features/time-picker/timePickerMeta.d.ts +90 -0
  95. package/dist/features/time-picker/timePickerMeta.d.ts.map +1 -0
  96. package/dist/features/time-picker/timePickerMeta.js +64 -0
  97. package/dist/features/time-picker/timePickerMeta.js.map +1 -0
  98. package/dist/index.d.ts +5 -10
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +5 -5
  101. package/dist/index.js.map +1 -1
  102. package/dist/layout/screen/meta.d.ts +1 -1
  103. package/dist/layout/screen-section/meta.d.ts +1 -1
  104. package/dist/metadata/allowedChildren.d.ts +3 -3
  105. package/dist/metadata/allowedChildren.d.ts.map +1 -1
  106. package/dist/metadata/allowedChildren.js +7 -0
  107. package/dist/metadata/allowedChildren.js.map +1 -1
  108. package/dist/metadata/bindableComponentMeta.d.ts +2 -2
  109. package/dist/metadata/componentMeta.js +5 -5
  110. package/dist/metadata/componentMeta.js.map +1 -1
  111. package/dist/patterns/message-bubble/meta.d.ts +1 -1
  112. package/dist/patterns/notice/meta.d.ts +1 -1
  113. package/dist/patterns/panel/meta.d.ts +1 -1
  114. package/dist/patterns/reader/meta.d.ts +2 -2
  115. package/dist/patterns/scanner/meta.d.ts +2 -2
  116. package/dist/registry.js +5 -5
  117. package/dist/registry.js.map +1 -1
  118. package/dist/{components/date-picker/types.d.ts → types/date-picker.d.ts} +6 -6
  119. package/dist/types/date-picker.d.ts.map +1 -0
  120. package/dist/types/date-picker.js +2 -0
  121. package/dist/types/date-picker.js.map +1 -0
  122. package/dist/{patterns/hero/types.d.ts → types/hero.d.ts} +3 -3
  123. package/dist/types/hero.d.ts.map +1 -0
  124. package/dist/types/hero.js +2 -0
  125. package/dist/types/hero.js.map +1 -0
  126. package/dist/{patterns/missing-element/types.d.ts → types/missing-element.d.ts} +2 -2
  127. package/dist/types/missing-element.d.ts.map +1 -0
  128. package/dist/types/missing-element.js +2 -0
  129. package/dist/types/missing-element.js.map +1 -0
  130. package/dist/{components/skeleton/types.d.ts → types/skeleton.d.ts} +3 -3
  131. package/dist/types/skeleton.d.ts.map +1 -0
  132. package/dist/types/skeleton.js +2 -0
  133. package/dist/types/skeleton.js.map +1 -0
  134. package/dist/{components/time-picker/types.d.ts → types/time-picker.d.ts} +2 -2
  135. package/dist/types/time-picker.d.ts.map +1 -0
  136. package/dist/types/time-picker.js +2 -0
  137. package/dist/types/time-picker.js.map +1 -0
  138. package/package.json +1 -1
  139. package/src/constants.ts +3 -0
  140. package/src/featureManifest.test.ts +12 -0
  141. package/src/features/bottom-sheet/public.test.ts +2 -2
  142. package/src/features/data-table/adapters/inbound/DataTable.tsx +1 -1
  143. package/src/{components/date-picker → features/date-picker/adapters/inbound}/DatePicker.tsx +41 -32
  144. package/src/features/date-picker/datePickerMeta.ts +58 -0
  145. package/src/features/date-picker/public.test.ts +15 -0
  146. package/src/features/date-picker/public.ts +2 -0
  147. package/src/features/date-picker/utils/localDate.test.ts +18 -0
  148. package/src/features/date-picker/utils/localDate.ts +29 -0
  149. package/src/{patterns/hero → features/hero/adapters/inbound}/Hero.tsx +6 -7
  150. package/src/features/hero/public.ts +2 -0
  151. package/src/{patterns → features}/missing-element/MissingElement.test.ts +6 -4
  152. package/src/{patterns/missing-element → features/missing-element/adapters/inbound}/MissingElement.tsx +6 -6
  153. package/src/features/missing-element/public.ts +2 -0
  154. package/src/{components/skeleton → features/skeleton/adapters/inbound}/Skeleton.tsx +4 -4
  155. package/src/{components/skeleton → features/skeleton/adapters/inbound}/SkeletonCard.tsx +5 -5
  156. package/src/{components/skeleton → features/skeleton/adapters/inbound}/SkeletonList.tsx +3 -3
  157. package/src/{components/skeleton → features/skeleton/adapters/inbound}/SkeletonText.tsx +3 -3
  158. package/src/features/skeleton/public.test.ts +24 -0
  159. package/src/features/skeleton/public.ts +13 -0
  160. package/src/features/skeleton/skeletonMeta.ts +88 -0
  161. package/src/{components/time-picker → features/time-picker/adapters/inbound}/TimePicker.tsx +9 -12
  162. package/src/features/time-picker/public.test.ts +14 -0
  163. package/src/features/time-picker/public.ts +2 -0
  164. package/src/features/time-picker/timePickerMeta.ts +65 -0
  165. package/src/index.ts +32 -18
  166. package/src/interactionPolicy.test.ts +3 -3
  167. package/src/metadata/allowedChildren.ts +7 -0
  168. package/src/metadata/componentMeta.test.ts +6 -0
  169. package/src/metadata/componentMeta.ts +10 -10
  170. package/src/registry.ts +5 -5
  171. package/src/{components/date-picker/types.ts → types/date-picker.ts} +5 -5
  172. package/src/{patterns/hero/types.ts → types/hero.ts} +2 -2
  173. package/src/{patterns/missing-element/types.ts → types/missing-element.ts} +1 -1
  174. package/src/{components/skeleton/types.ts → types/skeleton.ts} +2 -2
  175. package/src/{components/time-picker/types.ts → types/time-picker.ts} +1 -1
  176. package/dist/components/date-picker/DatePicker.d.ts.map +0 -1
  177. package/dist/components/date-picker/DatePicker.js.map +0 -1
  178. package/dist/components/date-picker/index.d.ts +0 -3
  179. package/dist/components/date-picker/index.d.ts.map +0 -1
  180. package/dist/components/date-picker/index.js +0 -2
  181. package/dist/components/date-picker/index.js.map +0 -1
  182. package/dist/components/date-picker/meta.d.ts +0 -9
  183. package/dist/components/date-picker/meta.d.ts.map +0 -1
  184. package/dist/components/date-picker/meta.js +0 -9
  185. package/dist/components/date-picker/meta.js.map +0 -1
  186. package/dist/components/date-picker/types.d.ts.map +0 -1
  187. package/dist/components/date-picker/types.js +0 -2
  188. package/dist/components/date-picker/types.js.map +0 -1
  189. package/dist/components/skeleton/Skeleton.d.ts.map +0 -1
  190. package/dist/components/skeleton/Skeleton.js.map +0 -1
  191. package/dist/components/skeleton/SkeletonCard.d.ts.map +0 -1
  192. package/dist/components/skeleton/SkeletonCard.js.map +0 -1
  193. package/dist/components/skeleton/SkeletonList.d.ts.map +0 -1
  194. package/dist/components/skeleton/SkeletonList.js.map +0 -1
  195. package/dist/components/skeleton/SkeletonText.d.ts.map +0 -1
  196. package/dist/components/skeleton/SkeletonText.js.map +0 -1
  197. package/dist/components/skeleton/index.d.ts +0 -6
  198. package/dist/components/skeleton/index.d.ts.map +0 -1
  199. package/dist/components/skeleton/index.js +0 -5
  200. package/dist/components/skeleton/index.js.map +0 -1
  201. package/dist/components/skeleton/meta.d.ts +0 -33
  202. package/dist/components/skeleton/meta.d.ts.map +0 -1
  203. package/dist/components/skeleton/meta.js +0 -33
  204. package/dist/components/skeleton/meta.js.map +0 -1
  205. package/dist/components/skeleton/types.d.ts.map +0 -1
  206. package/dist/components/skeleton/types.js +0 -2
  207. package/dist/components/skeleton/types.js.map +0 -1
  208. package/dist/components/time-picker/TimePicker.d.ts.map +0 -1
  209. package/dist/components/time-picker/TimePicker.js.map +0 -1
  210. package/dist/components/time-picker/index.d.ts +0 -3
  211. package/dist/components/time-picker/index.d.ts.map +0 -1
  212. package/dist/components/time-picker/index.js +0 -2
  213. package/dist/components/time-picker/index.js.map +0 -1
  214. package/dist/components/time-picker/meta.d.ts +0 -9
  215. package/dist/components/time-picker/meta.d.ts.map +0 -1
  216. package/dist/components/time-picker/meta.js +0 -9
  217. package/dist/components/time-picker/meta.js.map +0 -1
  218. package/dist/components/time-picker/types.d.ts.map +0 -1
  219. package/dist/components/time-picker/types.js +0 -2
  220. package/dist/components/time-picker/types.js.map +0 -1
  221. package/dist/patterns/hero/Hero.d.ts.map +0 -1
  222. package/dist/patterns/hero/Hero.js.map +0 -1
  223. package/dist/patterns/hero/index.d.ts +0 -3
  224. package/dist/patterns/hero/index.d.ts.map +0 -1
  225. package/dist/patterns/hero/index.js +0 -2
  226. package/dist/patterns/hero/index.js.map +0 -1
  227. package/dist/patterns/hero/meta.d.ts.map +0 -1
  228. package/dist/patterns/hero/meta.js.map +0 -1
  229. package/dist/patterns/hero/types.d.ts.map +0 -1
  230. package/dist/patterns/hero/types.js +0 -2
  231. package/dist/patterns/hero/types.js.map +0 -1
  232. package/dist/patterns/missing-element/MissingElement.d.ts.map +0 -1
  233. package/dist/patterns/missing-element/MissingElement.js.map +0 -1
  234. package/dist/patterns/missing-element/index.d.ts +0 -3
  235. package/dist/patterns/missing-element/index.d.ts.map +0 -1
  236. package/dist/patterns/missing-element/index.js +0 -2
  237. package/dist/patterns/missing-element/index.js.map +0 -1
  238. package/dist/patterns/missing-element/meta.d.ts.map +0 -1
  239. package/dist/patterns/missing-element/meta.js.map +0 -1
  240. package/dist/patterns/missing-element/types.d.ts.map +0 -1
  241. package/dist/patterns/missing-element/types.js +0 -2
  242. package/dist/patterns/missing-element/types.js.map +0 -1
  243. package/src/components/date-picker/index.ts +0 -2
  244. package/src/components/date-picker/meta.ts +0 -10
  245. package/src/components/skeleton/index.ts +0 -13
  246. package/src/components/skeleton/meta.ts +0 -37
  247. package/src/components/time-picker/index.ts +0 -2
  248. package/src/components/time-picker/meta.ts +0 -10
  249. package/src/patterns/hero/index.ts +0 -2
  250. package/src/patterns/missing-element/index.ts +0 -2
  251. /package/src/{patterns/hero/meta.ts → features/hero/heroMeta.ts} +0 -0
  252. /package/src/{patterns/missing-element/meta.ts → features/missing-element/missingElementMeta.ts} +0 -0
@@ -0,0 +1,29 @@
1
+ const LOCAL_DATE_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/u;
2
+
3
+ /*** Parse a calendar date without applying a UTC offset. */
4
+ export function parseLocalDate(value: string | null | undefined): Date | undefined {
5
+ if (!value) return undefined;
6
+
7
+ const match = LOCAL_DATE_PATTERN.exec(value);
8
+ if (!match) return undefined;
9
+
10
+ const year = Number(match[1]);
11
+ const month = Number(match[2]);
12
+ const day = Number(match[3]);
13
+ const parsed = new Date(year, month - 1, day);
14
+ parsed.setFullYear(year);
15
+
16
+ return parsed.getFullYear() === year &&
17
+ parsed.getMonth() === month - 1 &&
18
+ parsed.getDate() === day
19
+ ? parsed
20
+ : undefined;
21
+ }
22
+
23
+ /*** Serialize a Date as a local calendar date suitable for manifest state. */
24
+ export function formatLocalDate(value: Date): string {
25
+ const year = String(value.getFullYear()).padStart(4, '0');
26
+ const month = String(value.getMonth() + 1).padStart(2, '0');
27
+ const day = String(value.getDate()).padStart(2, '0');
28
+ return `${year}-${month}-${day}`;
29
+ }
@@ -1,12 +1,11 @@
1
1
  import React from 'react';
2
2
 
3
- import { Button } from '../../features/button/public';
4
- import { Card } from '../../features/card/public';
5
- import { Box, Grid, Stack } from '../../features/layout/public';
6
- import { Heading } from '../../features/typography/public';
7
- import { Text } from '../../features/typography/public';
8
- import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
9
- import type { HeroAction, HeroAlign, HeroProps } from './types';
3
+ import { withZoraThemeScope } from '../../../../theme/withZoraThemeScope';
4
+ import type { HeroAction, HeroAlign, HeroProps } from '../../../../types/hero';
5
+ import { Button } from '../../../button/public';
6
+ import { Card } from '../../../card/public';
7
+ import { Box, Grid, Stack } from '../../../layout/public';
8
+ import { Heading, Text } from '../../../typography/public';
10
9
 
11
10
  function HeroInner({
12
11
  themeId: _themeId,
@@ -0,0 +1,2 @@
1
+ export type { HeroAction, HeroAlign, HeroLayout, HeroProps, HeroTone } from '../../types/hero';
2
+ export { Hero } from './adapters/inbound/Hero';
@@ -1,7 +1,7 @@
1
1
  import { describe, expect, test } from 'bun:test';
2
2
 
3
3
  import { ZORA_BINDABLE_COMPONENT_META, ZORA_COMPONENT_META } from '../../metadata';
4
- import { missingElementMeta } from './meta';
4
+ import { missingElementMeta } from './missingElementMeta';
5
5
 
6
6
  describe('MissingElement draft contract', () => {
7
7
  test('is a release-blocking manifest leaf distinct from completed states', () => {
@@ -41,7 +41,9 @@ describe('MissingElement draft contract', () => {
41
41
  });
42
42
 
43
43
  test('visibly and accessibly identifies the gap while preserving its minimum dimensions', async () => {
44
- const source = await Bun.file('src/patterns/missing-element/MissingElement.tsx').text();
44
+ const source = await Bun.file(
45
+ 'src/features/missing-element/adapters/inbound/MissingElement.tsx',
46
+ ).text();
45
47
 
46
48
  expect(source).toContain('accessibilityLabel={accessibilityLabel}');
47
49
  expect(source).toContain('accessibilityRole="text"');
@@ -54,8 +56,8 @@ describe('MissingElement draft contract', () => {
54
56
 
55
57
  test('accepts the canonical interaction policy without owning interactive behavior', async () => {
56
58
  const [source, types] = await Promise.all([
57
- Bun.file('src/patterns/missing-element/MissingElement.tsx').text(),
58
- Bun.file('src/patterns/missing-element/types.ts').text(),
59
+ Bun.file('src/features/missing-element/adapters/inbound/MissingElement.tsx').text(),
60
+ Bun.file('src/types/missing-element.ts').text(),
59
61
  ]);
60
62
 
61
63
  expect(types).toContain('MissingElementProps extends ZoraBaseProps');
@@ -1,12 +1,12 @@
1
1
  import React from 'react';
2
2
  import { StyleSheet } from 'react-native';
3
3
 
4
- import { Badge } from '../../features/badge/public';
5
- import { Box, Stack } from '../../features/layout/public';
6
- import { Text } from '../../features/typography/public';
7
- import { useZoraTheme } from '../../theme/useZoraTheme';
8
- import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
9
- import type { MissingElementProps } from './types';
4
+ import { useZoraTheme } from '../../../../theme/useZoraTheme';
5
+ import { withZoraThemeScope } from '../../../../theme/withZoraThemeScope';
6
+ import type { MissingElementProps } from '../../../../types/missing-element';
7
+ import { Badge } from '../../../badge/public';
8
+ import { Box, Stack } from '../../../layout/public';
9
+ import { Text } from '../../../typography/public';
10
10
 
11
11
  /***
12
12
  * Renders the visible, non-interactive body of a draft missing-element marker.
@@ -0,0 +1,2 @@
1
+ export type { MissingElementProps } from '../../types/missing-element';
2
+ export { MissingElement } from './adapters/inbound/MissingElement';
@@ -1,9 +1,9 @@
1
1
  import React from 'react';
2
2
 
3
- import { Box } from '../../features/layout/public';
4
- import { useZoraTheme } from '../../theme/useZoraTheme';
5
- import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
6
- import type { SkeletonProps } from './types';
3
+ import { useZoraTheme } from '../../../../theme/useZoraTheme';
4
+ import { withZoraThemeScope } from '../../../../theme/withZoraThemeScope';
5
+ import type { SkeletonProps } from '../../../../types/skeleton';
6
+ import { Box } from '../../../layout/public';
7
7
 
8
8
  function SkeletonInner({
9
9
  themeId: _themeId,
@@ -1,12 +1,12 @@
1
1
  import React from 'react';
2
2
 
3
- import { ButtonGroup } from '../../features/button/public';
4
- import { Card } from '../../features/card/public';
5
- import { Stack } from '../../features/layout/public';
6
- import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
3
+ import { withZoraThemeScope } from '../../../../theme/withZoraThemeScope';
4
+ import type { SkeletonCardProps } from '../../../../types/skeleton';
5
+ import { ButtonGroup } from '../../../button/public';
6
+ import { Card } from '../../../card/public';
7
+ import { Stack } from '../../../layout/public';
7
8
  import { Skeleton } from './Skeleton';
8
9
  import { SkeletonText } from './SkeletonText';
9
- import type { SkeletonCardProps } from './types';
10
10
 
11
11
  function SkeletonCardInner({
12
12
  themeId: _themeId,
@@ -1,10 +1,10 @@
1
1
  import React from 'react';
2
2
 
3
- import { List, type ListRowProps } from '../../patterns/list';
4
- import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
3
+ import { List, type ListRowProps } from '../../../../patterns/list';
4
+ import { withZoraThemeScope } from '../../../../theme/withZoraThemeScope';
5
+ import type { SkeletonListProps } from '../../../../types/skeleton';
5
6
  import { Skeleton } from './Skeleton';
6
7
  import { SkeletonText } from './SkeletonText';
7
- import type { SkeletonListProps } from './types';
8
8
 
9
9
  function clampRows(rows: number): number {
10
10
  if (!Number.isFinite(rows)) {
@@ -1,9 +1,9 @@
1
1
  import React from 'react';
2
2
 
3
- import { Stack } from '../../features/layout/public';
4
- import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
3
+ import { withZoraThemeScope } from '../../../../theme/withZoraThemeScope';
4
+ import type { SkeletonTextProps } from '../../../../types/skeleton';
5
+ import { Stack } from '../../../layout/public';
5
6
  import { Skeleton } from './Skeleton';
6
- import type { SkeletonTextProps } from './types';
7
7
 
8
8
  function clampLines(lines: number): number {
9
9
  if (!Number.isFinite(lines)) {
@@ -0,0 +1,24 @@
1
+ import { expect, test } from 'bun:test';
2
+
3
+ import { ZORA_COMPONENT_META } from '../../metadata/componentMeta';
4
+
5
+ test('skeletons support direct authoring and automatic feature loading states', async () => {
6
+ const [dataTableSource, publicSource] = await Promise.all([
7
+ Bun.file('src/features/data-table/adapters/inbound/DataTable.tsx').text(),
8
+ Bun.file('src/features/skeleton/public.ts').text(),
9
+ ]);
10
+
11
+ expect(ZORA_COMPONENT_META.Skeleton.directManifestNode).toBe(true);
12
+ expect(ZORA_COMPONENT_META.SkeletonCard.directManifestNode).toBe(true);
13
+ expect(ZORA_COMPONENT_META.SkeletonList.directManifestNode).toBe(true);
14
+ expect(ZORA_COMPONENT_META.SkeletonText.directManifestNode).toBe(true);
15
+ expect(publicSource).toContain('Skeleton');
16
+ expect(publicSource).toContain('SkeletonCard');
17
+ expect(publicSource).toContain('SkeletonList');
18
+ expect(publicSource).toContain('SkeletonText');
19
+ expect(ZORA_COMPONENT_META.SkeletonList.bindings?.props?.rows?.value.type).toBe('number');
20
+
21
+ expect(dataTableSource).toContain("from '../../../skeleton/public'");
22
+ expect(dataTableSource).toContain('if (loading)');
23
+ expect(dataTableSource).toContain('<SkeletonList rows={loadingRows}');
24
+ });
@@ -0,0 +1,13 @@
1
+ export type {
2
+ SkeletonCardProps,
3
+ SkeletonDimension,
4
+ SkeletonListProps,
5
+ SkeletonListVariant,
6
+ SkeletonProps,
7
+ SkeletonRadius,
8
+ SkeletonTextProps,
9
+ } from '../../types/skeleton';
10
+ export { Skeleton } from './adapters/inbound/Skeleton';
11
+ export { SkeletonCard } from './adapters/inbound/SkeletonCard';
12
+ export { SkeletonList } from './adapters/inbound/SkeletonList';
13
+ export { SkeletonText } from './adapters/inbound/SkeletonText';
@@ -0,0 +1,88 @@
1
+ import type { ZoraComponentMeta } from '../../metadata';
2
+
3
+ export const skeletonMeta = {
4
+ name: 'Skeleton',
5
+ category: 'component',
6
+ description: 'Generic visual placeholder for a loading content region.',
7
+ directManifestNode: true,
8
+ allowedChildren: [],
9
+ blueprint: {
10
+ label: 'Skeleton',
11
+ defaultProps: { height: 16, radius: 'm' },
12
+ },
13
+ props: {
14
+ width: { type: 'number', category: 'Layout', label: 'Width' },
15
+ height: { type: 'number', category: 'Layout', label: 'Height', default: 16 },
16
+ radius: { type: 'radius', category: 'Appearance', label: 'Radius', default: 'm' },
17
+ },
18
+ } as const satisfies ZoraComponentMeta;
19
+
20
+ export const skeletonTextMeta = {
21
+ name: 'SkeletonText',
22
+ category: 'component',
23
+ description: 'Multi-line placeholder for loading text content.',
24
+ directManifestNode: true,
25
+ allowedChildren: [],
26
+ blueprint: {
27
+ label: 'Skeleton text',
28
+ defaultProps: { lines: 3, lineHeight: 12, gap: 'xs' },
29
+ },
30
+ props: {
31
+ lines: { type: 'number', category: 'Content', label: 'Lines', default: 3 },
32
+ lineHeight: { type: 'number', category: 'Layout', label: 'Line height', default: 12 },
33
+ gap: { type: 'spacing', category: 'Spacing', label: 'Gap', default: 'xs' },
34
+ width: { type: 'number', category: 'Layout', label: 'Width' },
35
+ lastLineWidth: { type: 'number', category: 'Layout', label: 'Last line width' },
36
+ },
37
+ } as const satisfies ZoraComponentMeta;
38
+
39
+ export const skeletonCardMeta = {
40
+ name: 'SkeletonCard',
41
+ category: 'component',
42
+ description: 'Card-shaped placeholder for loading media, copy, and actions.',
43
+ directManifestNode: true,
44
+ allowedChildren: [],
45
+ blueprint: {
46
+ label: 'Skeleton card',
47
+ defaultProps: { media: false, actions: false, lines: 3, compact: false },
48
+ },
49
+ props: {
50
+ media: { type: 'boolean', category: 'Content', label: 'Media', default: false },
51
+ actions: { type: 'boolean', category: 'Content', label: 'Actions', default: false },
52
+ lines: { type: 'number', category: 'Content', label: 'Lines', default: 3 },
53
+ compact: { type: 'boolean', category: 'Layout', label: 'Compact', default: false },
54
+ },
55
+ } as const satisfies ZoraComponentMeta;
56
+
57
+ export const skeletonListMeta = {
58
+ name: 'SkeletonList',
59
+ category: 'component',
60
+ description: 'List-shaped placeholder for loading rows with optional leading content.',
61
+ directManifestNode: true,
62
+ allowedChildren: [],
63
+ blueprint: {
64
+ label: 'Skeleton list',
65
+ defaultProps: {
66
+ rows: 5,
67
+ avatar: false,
68
+ media: false,
69
+ lines: 2,
70
+ variant: 'divider',
71
+ compact: false,
72
+ },
73
+ },
74
+ props: {
75
+ rows: { type: 'number', category: 'Content', label: 'Rows', default: 5 },
76
+ avatar: { type: 'boolean', category: 'Content', label: 'Avatar', default: false },
77
+ media: { type: 'boolean', category: 'Content', label: 'Media', default: false },
78
+ lines: { type: 'number', category: 'Content', label: 'Lines', default: 2 },
79
+ variant: {
80
+ type: 'enum',
81
+ category: 'Appearance',
82
+ label: 'Variant',
83
+ enum: ['divider', 'card'],
84
+ default: 'divider',
85
+ },
86
+ compact: { type: 'boolean', category: 'Layout', label: 'Compact', default: false },
87
+ },
88
+ } as const satisfies ZoraComponentMeta;
@@ -2,12 +2,12 @@ import { Field } from '@ankhorage/surface';
2
2
  import React from 'react';
3
3
  import { ScrollView, StyleSheet } from 'react-native';
4
4
 
5
- import { useBottomSheet } from '../../features/bottom-sheet/public';
6
- import { Button } from '../../features/button/public';
7
- import { Stack } from '../../features/layout/public';
8
- import { Text } from '../../features/typography/public';
9
- import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
10
- import type { TimePickerProps } from './types';
5
+ import { withZoraThemeScope } from '../../../../theme/withZoraThemeScope';
6
+ import type { TimePickerProps } from '../../../../types/time-picker';
7
+ import { useBottomSheet } from '../../../bottom-sheet/public';
8
+ import { Button } from '../../../button/public';
9
+ import { Stack } from '../../../layout/public';
10
+ import { Text } from '../../../typography/public';
11
11
 
12
12
  const MINUTES_PER_DAY = 24 * 60;
13
13
  const DEFAULT_STEP_MINUTES = 30;
@@ -64,12 +64,9 @@ function generateTimeOptions({
64
64
  const step = resolveStepMinutes(stepMinutes);
65
65
  const min = parseTimeToMinutes(minTime) ?? 0;
66
66
  const max = parseTimeToMinutes(maxTime) ?? MINUTES_PER_DAY - 1;
67
- const options: string[] = [];
68
-
69
- for (let minute = 0; minute < MINUTES_PER_DAY; minute += step) {
70
- if (minute >= min && minute <= max) options.push(formatMinutes(minute));
71
- }
72
- return options;
67
+ return Array.from({ length: Math.ceil(MINUTES_PER_DAY / step) }, (_, index) => index * step)
68
+ .filter((minute) => minute >= min && minute <= max)
69
+ .map(formatMinutes);
73
70
  }
74
71
 
75
72
  function TimePickerInner({
@@ -0,0 +1,14 @@
1
+ import { expect, test } from 'bun:test';
2
+
3
+ import { ZORA_COMPONENT_META } from '../../metadata/componentMeta';
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();
7
+ const meta = ZORA_COMPONENT_META.TimePicker;
8
+
9
+ expect(meta.directManifestNode).toBe(true);
10
+ expect(meta.props.value?.type).toBe('string');
11
+ expect(meta.events?.valueChange?.eventType).toBe('timePicker.valueChange');
12
+ expect(meta.bindings?.props?.value?.value.type).toBe('string');
13
+ expect(source).toContain('useBottomSheet()');
14
+ });
@@ -0,0 +1,2 @@
1
+ export type { TimePickerProps, TimePickerValue } from '../../types/time-picker';
2
+ export { TimePicker } from './adapters/inbound/TimePicker';
@@ -0,0 +1,65 @@
1
+ import type { ZoraComponentMeta } from '../../metadata';
2
+
3
+ export const timePickerMeta = {
4
+ name: 'TimePicker',
5
+ category: 'component',
6
+ description: 'Captures a local HH:mm time through the shared BottomSheet picker host.',
7
+ directManifestNode: true,
8
+ allowedChildren: [],
9
+ blueprint: {
10
+ label: 'Time picker',
11
+ defaultProps: {
12
+ value: null,
13
+ placeholder: 'Choose time',
14
+ stepMinutes: 30,
15
+ disabled: false,
16
+ required: false,
17
+ },
18
+ },
19
+ events: {
20
+ valueChange: {
21
+ label: 'Value change',
22
+ eventType: 'timePicker.valueChange',
23
+ description: 'Emitted when an HH:mm time value is selected.',
24
+ payloadFields: [{ path: 'value', type: 'string', label: 'Value' }],
25
+ },
26
+ },
27
+ props: {
28
+ value: {
29
+ type: 'string',
30
+ category: 'State',
31
+ label: 'Value',
32
+ default: null,
33
+ authoring: { authority: 'instance' },
34
+ },
35
+ label: { type: 'string', category: 'Content', label: 'Label' },
36
+ description: { type: 'string', category: 'Content', label: 'Description' },
37
+ error: { type: 'string', category: 'Validation', label: 'Error' },
38
+ placeholder: {
39
+ type: 'string',
40
+ category: 'Content',
41
+ label: 'Placeholder',
42
+ default: 'Choose time',
43
+ },
44
+ minTime: { type: 'string', category: 'Validation', label: 'Minimum time' },
45
+ maxTime: { type: 'string', category: 'Validation', label: 'Maximum time' },
46
+ stepMinutes: {
47
+ type: 'number',
48
+ category: 'Behavior',
49
+ label: 'Step in minutes',
50
+ default: 30,
51
+ },
52
+ disabled: {
53
+ type: 'boolean',
54
+ category: 'State',
55
+ label: 'Disabled',
56
+ default: false,
57
+ },
58
+ required: {
59
+ type: 'boolean',
60
+ category: 'Validation',
61
+ label: 'Required',
62
+ default: false,
63
+ },
64
+ },
65
+ } as const satisfies ZoraComponentMeta;
package/src/index.ts CHANGED
@@ -2,8 +2,6 @@ export type { AppBarMode, AppBarOverflowAction, AppBarProps } from './components
2
2
  export { AppBar } from './components/app-bar';
3
3
  export type { BreadcrumbItem, BreadcrumbsProps } from './components/breadcrumbs';
4
4
  export { Breadcrumbs } from './components/breadcrumbs';
5
- export type { DatePickerProps, DatePickerValue } from './components/date-picker';
6
- export { DatePicker } from './components/date-picker';
7
5
  export type {
8
6
  GradientColor,
9
7
  GradientColors,
@@ -27,20 +25,8 @@ export type { SearchBarProps } from './components/search-bar';
27
25
  export { SearchBar } from './components/search-bar';
28
26
  export type { SelectOption, SelectProps } from './components/select';
29
27
  export { Select } from './components/select';
30
- export type {
31
- SkeletonCardProps,
32
- SkeletonDimension,
33
- SkeletonListProps,
34
- SkeletonListVariant,
35
- SkeletonProps,
36
- SkeletonRadius,
37
- SkeletonTextProps,
38
- } from './components/skeleton';
39
- export { Skeleton, SkeletonCard, SkeletonList, SkeletonText } from './components/skeleton';
40
28
  export type { TabItem, TabsProps, TabsVariant } from './components/tabs';
41
29
  export { Tabs } from './components/tabs';
42
- export type { TimePickerProps, TimePickerValue } from './components/time-picker';
43
- export { TimePicker } from './components/time-picker';
44
30
  export type { ToastOptions, ToastProps, ToastProviderProps, ToastStatus } from './components/toast';
45
31
  export { Toast, ToastProvider, useToast } from './components/toast';
46
32
  export type { ToolbarActionProps, ToolbarPosition, ToolbarProps } from './components/toolbar';
@@ -100,6 +86,11 @@ export type {
100
86
  DataTableSortState,
101
87
  } from './features/data-table/public';
102
88
  export { DataTable } from './features/data-table/public';
89
+ export {
90
+ DatePicker,
91
+ type DatePickerProps,
92
+ type DatePickerValue,
93
+ } from './features/date-picker/public';
103
94
  export {
104
95
  EmptyState,
105
96
  type EmptyStateAction,
@@ -150,6 +141,14 @@ export {
150
141
  type TextInputProps,
151
142
  type TextInputTrailingAction,
152
143
  } from './features/form/text-input/public';
144
+ export {
145
+ Hero,
146
+ type HeroAction,
147
+ type HeroAlign,
148
+ type HeroLayout,
149
+ type HeroProps,
150
+ type HeroTone,
151
+ } from './features/hero/public';
153
152
  export type { IconProps } from './features/icon/public';
154
153
  export { Icon } from './features/icon/public';
155
154
  export type { ImageFit, ImageProps, SurfaceImageSource } from './features/image/public';
@@ -183,14 +182,33 @@ export type {
183
182
  ManifestSectionListProps,
184
183
  } from './features/list/public';
185
184
  export { FlatList, SectionList } from './features/list/public';
185
+ export { MissingElement, type MissingElementProps } from './features/missing-element/public';
186
186
  export {
187
187
  Progress,
188
188
  type ProgressProps,
189
189
  ProgressRing,
190
190
  type ProgressRingProps,
191
191
  } from './features/progress/public';
192
+ export {
193
+ Skeleton,
194
+ SkeletonCard,
195
+ type SkeletonCardProps,
196
+ type SkeletonDimension,
197
+ SkeletonList,
198
+ type SkeletonListProps,
199
+ type SkeletonListVariant,
200
+ type SkeletonProps,
201
+ type SkeletonRadius,
202
+ SkeletonText,
203
+ type SkeletonTextProps,
204
+ } from './features/skeleton/public';
192
205
  export type { SurfaceProps, SurfaceVariant } from './features/surface/public';
193
206
  export { Surface } from './features/surface/public';
207
+ export {
208
+ TimePicker,
209
+ type TimePickerProps,
210
+ type TimePickerValue,
211
+ } from './features/time-picker/public';
194
212
  export type {
195
213
  HeadingAlign,
196
214
  HeadingColor,
@@ -320,8 +338,6 @@ export type { DisclosureSectionProps } from './patterns/disclosure-section';
320
338
  export { DisclosureSection } from './patterns/disclosure-section';
321
339
  export type { FilterBarProps } from './patterns/filter-bar';
322
340
  export { FilterBar } from './patterns/filter-bar';
323
- export type { HeroAction, HeroAlign, HeroLayout, HeroProps, HeroTone } from './patterns/hero';
324
- export { Hero } from './patterns/hero';
325
341
  export type { InspectorFieldProps } from './patterns/inspector-field';
326
342
  export { InspectorField } from './patterns/inspector-field';
327
343
  export type {
@@ -340,8 +356,6 @@ export type {
340
356
  MessageBubbleStatus,
341
357
  } from './patterns/message-bubble';
342
358
  export { MessageBubble } from './patterns/message-bubble';
343
- export type { MissingElementProps } from './patterns/missing-element';
344
- export { MissingElement } from './patterns/missing-element';
345
359
  export type { NoticeProps } from './patterns/notice';
346
360
  export { Notice } from './patterns/notice';
347
361
  export type { PanelProps } from './patterns/panel';
@@ -40,7 +40,7 @@ describe('InteractionPolicy declaration', () => {
40
40
  readComponent('app-bar', 'types.ts'),
41
41
  readComponent('breadcrumbs', 'types.ts'),
42
42
  readSource('types/empty-state.ts'),
43
- readPattern('hero', 'types.ts'),
43
+ readSource('types/hero.ts'),
44
44
  readSource('types/product-card.ts'),
45
45
  readPattern('reader', 'types.ts'),
46
46
  readPattern('scanner', 'types.ts'),
@@ -115,14 +115,14 @@ describe('EmptyState', () => {
115
115
 
116
116
  describe('Hero', () => {
117
117
  test('forwards interactionPolicy to Card', () => {
118
- const source = readPattern('hero', 'Hero.tsx');
118
+ const source = readSource('features/hero/adapters/inbound/Hero.tsx');
119
119
 
120
120
  expect(source).not.toMatch(/interactionPolicy:\s*_interactionPolicy/);
121
121
  expect(source).toMatch(/<Card[\s\S]*?interactionPolicy=\{interactionPolicy\}/);
122
122
  });
123
123
 
124
124
  test('passes interactionPolicy through renderAction to internal Buttons', () => {
125
- const source = readPattern('hero', 'Hero.tsx');
125
+ const source = readSource('features/hero/adapters/inbound/Hero.tsx');
126
126
 
127
127
  expect(source).toMatch(
128
128
  /function renderAction\([\s\S]*?interactionPolicy: HeroProps\['interactionPolicy'\]/,
@@ -9,6 +9,11 @@ export const CONTAINER_ALLOWED_CHILDREN = [
9
9
  'Chip',
10
10
  'ChipGroup',
11
11
  'DataTable',
12
+ 'DatePicker',
13
+ 'Skeleton',
14
+ 'SkeletonCard',
15
+ 'SkeletonList',
16
+ 'SkeletonText',
12
17
  'IconButton',
13
18
  'Uploader',
14
19
  'FlatList',
@@ -24,12 +29,14 @@ export const CONTAINER_ALLOWED_CHILDREN = [
24
29
  'Heading',
25
30
  'Icon',
26
31
  'Image',
32
+ 'Hero',
27
33
  'KeyboardAvoidingView',
28
34
  'Button',
29
35
  'ButtonGroup',
30
36
  'RadioGroup',
31
37
  'ThemeModeToggle',
32
38
  'TextInput',
39
+ 'TimePicker',
33
40
  'Form',
34
41
  'Card',
35
42
  'Panel',
@@ -143,6 +143,11 @@ describe('ZORA_COMPONENT_META invariants', () => {
143
143
  'Chip',
144
144
  'ChipGroup',
145
145
  'DataTable',
146
+ 'DatePicker',
147
+ 'Skeleton',
148
+ 'SkeletonCard',
149
+ 'SkeletonList',
150
+ 'SkeletonText',
146
151
  'IconButton',
147
152
  'MetricCard',
148
153
  'Uploader',
@@ -171,6 +176,7 @@ describe('ZORA_COMPONENT_META invariants', () => {
171
176
  'ProgressRing',
172
177
  'ReaderSurface',
173
178
  'MissingElement',
179
+ 'TimePicker',
174
180
  ]);
175
181
 
176
182
  const expectedContainerNodes = new Set([