@ankhorage/zora 3.0.2 → 3.1.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 (76) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -1
  3. package/dist/components/card/meta.d.ts +1 -1
  4. package/dist/components/text/Text.d.ts.map +1 -1
  5. package/dist/components/text/Text.js +2 -2
  6. package/dist/components/text/Text.js.map +1 -1
  7. package/dist/components/text/types.d.ts +2 -1
  8. package/dist/components/text/types.d.ts.map +1 -1
  9. package/dist/components/text/types.js.map +1 -1
  10. package/dist/foundation/meta.d.ts +4 -4
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +1 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/layout/screen/meta.d.ts +1 -1
  16. package/dist/layout/screen-section/meta.d.ts +1 -1
  17. package/dist/metadata/allowedChildren.d.ts +3 -3
  18. package/dist/metadata/allowedChildren.d.ts.map +1 -1
  19. package/dist/metadata/allowedChildren.js +1 -0
  20. package/dist/metadata/allowedChildren.js.map +1 -1
  21. package/dist/metadata/bindableComponentMeta.d.ts +485 -0
  22. package/dist/metadata/bindableComponentMeta.d.ts.map +1 -1
  23. package/dist/metadata/bindableComponentMeta.js +102 -0
  24. package/dist/metadata/bindableComponentMeta.js.map +1 -1
  25. package/dist/metadata/componentMeta.d.ts.map +1 -1
  26. package/dist/metadata/componentMeta.js +2 -0
  27. package/dist/metadata/componentMeta.js.map +1 -1
  28. package/dist/patterns/message-bubble/meta.d.ts +1 -1
  29. package/dist/patterns/notice/meta.d.ts +1 -1
  30. package/dist/patterns/panel/meta.d.ts +1 -1
  31. package/dist/patterns/post-card/meta.d.ts +1 -1
  32. package/dist/patterns/reader/ReaderSurface.d.ts +11 -0
  33. package/dist/patterns/reader/ReaderSurface.d.ts.map +1 -0
  34. package/dist/patterns/reader/ReaderSurface.js +95 -0
  35. package/dist/patterns/reader/ReaderSurface.js.map +1 -0
  36. package/dist/patterns/reader/index.d.ts +4 -0
  37. package/dist/patterns/reader/index.d.ts.map +1 -0
  38. package/dist/patterns/reader/index.js +3 -0
  39. package/dist/patterns/reader/index.js.map +1 -0
  40. package/dist/patterns/reader/meta.d.ts +328 -0
  41. package/dist/patterns/reader/meta.d.ts.map +1 -0
  42. package/dist/patterns/reader/meta.js +293 -0
  43. package/dist/patterns/reader/meta.js.map +1 -0
  44. package/dist/patterns/reader/resolveReaderProgress.d.ts +6 -0
  45. package/dist/patterns/reader/resolveReaderProgress.d.ts.map +1 -0
  46. package/dist/patterns/reader/resolveReaderProgress.js +17 -0
  47. package/dist/patterns/reader/resolveReaderProgress.js.map +1 -0
  48. package/dist/patterns/reader/types.d.ts +69 -0
  49. package/dist/patterns/reader/types.d.ts.map +1 -0
  50. package/dist/patterns/reader/types.js +2 -0
  51. package/dist/patterns/reader/types.js.map +1 -0
  52. package/dist/patterns/scanner/meta.d.ts +2 -2
  53. package/dist/registry.d.ts.map +1 -1
  54. package/dist/registry.js +2 -0
  55. package/dist/registry.js.map +1 -1
  56. package/dist/theme/useZoraTheme.d.ts +1 -1
  57. package/package.json +3 -3
  58. package/src/components/text/Text.tsx +2 -0
  59. package/src/components/text/types.ts +7 -1
  60. package/src/expo57Migration.test.ts +18 -14
  61. package/src/index.ts +14 -0
  62. package/src/interactionPolicy.test.ts +30 -0
  63. package/src/metadata/allowedChildren.ts +1 -0
  64. package/src/metadata/bindableComponentMeta.test.ts +30 -0
  65. package/src/metadata/bindableComponentMeta.ts +102 -0
  66. package/src/metadata/componentMeta.test.ts +36 -0
  67. package/src/metadata/componentMeta.ts +2 -0
  68. package/src/patterns/reader/ReaderSurface.test.ts +46 -0
  69. package/src/patterns/reader/ReaderSurface.tsx +348 -0
  70. package/src/patterns/reader/index.ts +15 -0
  71. package/src/patterns/reader/meta.ts +296 -0
  72. package/src/patterns/reader/resolveReaderProgress.test.ts +31 -0
  73. package/src/patterns/reader/resolveReaderProgress.ts +29 -0
  74. package/src/patterns/reader/types.ts +80 -0
  75. package/src/registry.ts +2 -0
  76. package/src/showcaseCoverage.test.ts +1 -0
@@ -0,0 +1,17 @@
1
+ export function resolveReaderProgress({ progress, page, pageCount, }) {
2
+ if (progress !== undefined && Number.isFinite(progress)) {
3
+ return Math.min(1, Math.max(0, progress));
4
+ }
5
+ if (page === undefined ||
6
+ pageCount === undefined ||
7
+ !Number.isFinite(page) ||
8
+ !Number.isFinite(pageCount) ||
9
+ pageCount < 1) {
10
+ return 0;
11
+ }
12
+ if (pageCount === 1) {
13
+ return 1;
14
+ }
15
+ return Math.min(1, Math.max(0, (page - 1) / (pageCount - 1)));
16
+ }
17
+ //# sourceMappingURL=resolveReaderProgress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveReaderProgress.js","sourceRoot":"","sources":["../../../src/patterns/reader/resolveReaderProgress.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,qBAAqB,CAAC,EACpC,QAAQ,EACR,IAAI,EACJ,SAAS,GAKV;IACC,IAAI,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,IACE,IAAI,KAAK,SAAS;QAClB,SAAS,KAAK,SAAS;QACvB,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QACtB,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC3B,SAAS,GAAG,CAAC,EACb,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;QACpB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC","sourcesContent":["export function resolveReaderProgress({\n progress,\n page,\n pageCount,\n}: {\n progress?: number;\n page?: number;\n pageCount?: number;\n}): number {\n if (progress !== undefined && Number.isFinite(progress)) {\n return Math.min(1, Math.max(0, progress));\n }\n\n if (\n page === undefined ||\n pageCount === undefined ||\n !Number.isFinite(page) ||\n !Number.isFinite(pageCount) ||\n pageCount < 1\n ) {\n return 0;\n }\n\n if (pageCount === 1) {\n return 1;\n }\n\n return Math.min(1, Math.max(0, (page - 1) / (pageCount - 1)));\n}\n"]}
@@ -0,0 +1,69 @@
1
+ import type React from 'react';
2
+ import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
3
+ export type ReaderDocumentFormat = 'epub' | 'pdf';
4
+ export type ReaderStatus = 'idle' | 'loading' | 'ready' | 'error';
5
+ export type ReaderNavigationTrigger = 'swipe' | 'previousControl' | 'nextControl' | 'keyboard' | 'location';
6
+ export interface ReaderLocationChangeEvent {
7
+ format: ReaderDocumentFormat;
8
+ locator: string;
9
+ page: number;
10
+ pageCount?: number;
11
+ progression: number;
12
+ chapterId?: string;
13
+ chapterTitle?: string;
14
+ trigger: ReaderNavigationTrigger;
15
+ }
16
+ export type ReaderErrorCode = 'invalid-document' | 'load-failed' | 'protected-document' | 'unsupported-format';
17
+ export interface ReaderErrorEvent {
18
+ code: ReaderErrorCode;
19
+ format?: ReaderDocumentFormat;
20
+ message: string;
21
+ }
22
+ export type ReaderColorScheme = 'system' | 'light' | 'dark' | 'sepia';
23
+ export type ReaderLineHeight = 'compact' | 'normal' | 'relaxed';
24
+ export type ReaderResolvedSource = string | number | {
25
+ readonly uri: string;
26
+ };
27
+ export interface ReaderExternalLinkEvent {
28
+ url: string;
29
+ }
30
+ export interface ReaderSurfaceProps extends ZoraBaseProps {
31
+ source?: ReaderResolvedSource | null;
32
+ format: ReaderDocumentFormat;
33
+ location?: string;
34
+ status?: ReaderStatus;
35
+ page?: number;
36
+ pageCount?: number;
37
+ progress?: number;
38
+ canGoPrevious?: boolean;
39
+ canGoNext?: boolean;
40
+ title?: string;
41
+ subtitle?: string;
42
+ chapterLabel?: string;
43
+ pageLabel?: string;
44
+ previousPageLabel?: string;
45
+ nextPageLabel?: string;
46
+ contentsLabel?: string;
47
+ appearanceLabel?: string;
48
+ highlightLabel?: string;
49
+ loadingLabel?: string;
50
+ errorTitle?: string;
51
+ unavailableTitle?: string;
52
+ showChrome?: boolean;
53
+ readerColorScheme?: ReaderColorScheme;
54
+ fontScale?: number;
55
+ lineHeight?: ReaderLineHeight;
56
+ highlighted?: boolean;
57
+ viewport?: React.ReactNode;
58
+ headerActions?: React.ReactNode;
59
+ footerActions?: React.ReactNode;
60
+ onPreviousPage?: () => void | Promise<void>;
61
+ onNextPage?: () => void | Promise<void>;
62
+ onLocationChange?: (event: ReaderLocationChangeEvent) => void | Promise<void>;
63
+ onOpenContents?: () => void | Promise<void>;
64
+ onOpenAppearance?: () => void | Promise<void>;
65
+ onToggleHighlight?: () => void | Promise<void>;
66
+ onOpenExternalLink?: (event: ReaderExternalLinkEvent) => void | Promise<void>;
67
+ onReaderError?: (event: ReaderErrorEvent) => void | Promise<void>;
68
+ }
69
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/patterns/reader/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/patterns/reader/types.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nimport type { ZoraBaseProps } from '../../theme/ZoraBaseProps';\n\nexport type ReaderDocumentFormat = 'epub' | 'pdf';\n\nexport type ReaderStatus = 'idle' | 'loading' | 'ready' | 'error';\n\nexport type ReaderNavigationTrigger =\n 'swipe' | 'previousControl' | 'nextControl' | 'keyboard' | 'location';\n\nexport interface ReaderLocationChangeEvent {\n format: ReaderDocumentFormat;\n locator: string;\n page: number;\n pageCount?: number;\n progression: number;\n chapterId?: string;\n chapterTitle?: string;\n trigger: ReaderNavigationTrigger;\n}\n\nexport type ReaderErrorCode =\n 'invalid-document' | 'load-failed' | 'protected-document' | 'unsupported-format';\n\nexport interface ReaderErrorEvent {\n code: ReaderErrorCode;\n format?: ReaderDocumentFormat;\n message: string;\n}\n\nexport type ReaderColorScheme = 'system' | 'light' | 'dark' | 'sepia';\n\nexport type ReaderLineHeight = 'compact' | 'normal' | 'relaxed';\n\nexport type ReaderResolvedSource = string | number | { readonly uri: string };\n\nexport interface ReaderExternalLinkEvent {\n url: string;\n}\n\nexport interface ReaderSurfaceProps extends ZoraBaseProps {\n source?: ReaderResolvedSource | null;\n format: ReaderDocumentFormat;\n location?: string;\n status?: ReaderStatus;\n page?: number;\n pageCount?: number;\n progress?: number;\n canGoPrevious?: boolean;\n canGoNext?: boolean;\n title?: string;\n subtitle?: string;\n chapterLabel?: string;\n pageLabel?: string;\n previousPageLabel?: string;\n nextPageLabel?: string;\n contentsLabel?: string;\n appearanceLabel?: string;\n highlightLabel?: string;\n loadingLabel?: string;\n errorTitle?: string;\n unavailableTitle?: string;\n showChrome?: boolean;\n readerColorScheme?: ReaderColorScheme;\n fontScale?: number;\n lineHeight?: ReaderLineHeight;\n highlighted?: boolean;\n viewport?: React.ReactNode;\n headerActions?: React.ReactNode;\n footerActions?: React.ReactNode;\n onPreviousPage?: () => void | Promise<void>;\n onNextPage?: () => void | Promise<void>;\n onLocationChange?: (event: ReaderLocationChangeEvent) => void | Promise<void>;\n onOpenContents?: () => void | Promise<void>;\n onOpenAppearance?: () => void | Promise<void>;\n onToggleHighlight?: () => void | Promise<void>;\n onOpenExternalLink?: (event: ReaderExternalLinkEvent) => void | Promise<void>;\n onReaderError?: (event: ReaderErrorEvent) => void | Promise<void>;\n}\n"]}
@@ -105,7 +105,7 @@ export declare const barcodeScannerViewMeta: {
105
105
  readonly category: "pattern";
106
106
  readonly description: "Composed scanner shell with permission, camera slot, scan overlay, and manual entry affordance.";
107
107
  readonly directManifestNode: true;
108
- readonly allowedChildren: readonly ["Box", "Stack", "Grid", "Container", "Divider", "Text", "Heading", "Button", "ButtonGroup", "ThemeModeToggle", "Input", "Textarea", "FormField", "Card", "Panel", "Notice", "EmptyState", "SectionHeader", "SettingsRow", "PostCard", "ChatListItem", "MessageBubble"];
108
+ readonly allowedChildren: readonly ["Box", "Stack", "Grid", "Container", "Divider", "Text", "Heading", "Button", "ButtonGroup", "ThemeModeToggle", "Input", "Textarea", "FormField", "Card", "Panel", "Notice", "EmptyState", "SectionHeader", "SettingsRow", "PostCard", "ChatListItem", "MessageBubble", "ReaderSurface"];
109
109
  readonly requirements: {
110
110
  readonly permissions: readonly [{
111
111
  readonly permission: "camera";
@@ -145,7 +145,7 @@ export declare const barcodeScannerViewMeta: {
145
145
  };
146
146
  readonly children: {
147
147
  readonly label: "Scanner footer";
148
- readonly allowedChildren: readonly ["Box", "Stack", "Grid", "Container", "Divider", "Text", "Heading", "Button", "ButtonGroup", "ThemeModeToggle", "Input", "Textarea", "FormField", "Card", "Panel", "Notice", "EmptyState", "SectionHeader", "SettingsRow", "PostCard", "ChatListItem", "MessageBubble"];
148
+ readonly allowedChildren: readonly ["Box", "Stack", "Grid", "Container", "Divider", "Text", "Heading", "Button", "ButtonGroup", "ThemeModeToggle", "Input", "Textarea", "FormField", "Card", "Panel", "Notice", "EmptyState", "SectionHeader", "SettingsRow", "PostCard", "ChatListItem", "MessageBubble", "ReaderSurface"];
149
149
  };
150
150
  };
151
151
  readonly props: {
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAoG/B,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;AA0IhF,eAAO,MAAM,uBAAuB,EAAE,qBAAgD,CAAC"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAqG/B,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;AA2IhF,eAAO,MAAM,uBAAuB,EAAE,qBAAgD,CAAC"}
package/dist/registry.js CHANGED
@@ -64,6 +64,7 @@ import { Notice } from './patterns/notice';
64
64
  import { Panel } from './patterns/panel';
65
65
  import { PostCard } from './patterns/post-card';
66
66
  import { ProductCard } from './patterns/product-card';
67
+ import { ReaderSurface } from './patterns/reader';
67
68
  import { ResponsivePanel } from './patterns/responsive-panel';
68
69
  import { BarcodeScannerView, CameraPermissionView, ScanOverlay } from './patterns/scanner';
69
70
  import { SectionHeader } from './patterns/section-header';
@@ -173,6 +174,7 @@ const _ZORA_COMPONENT_REGISTRY = {
173
174
  PostCard,
174
175
  ProductCard,
175
176
  ResponsivePanel,
177
+ ReaderSurface,
176
178
  BarcodeScannerView,
177
179
  CameraPermissionView,
178
180
  ScanOverlay,
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InteractionPolicyProps } from '@ankhorage/surface';\nimport type React from 'react';\n\nimport { ActionSheet, ActionSheetItem } from './components/action-sheet';\nimport { AppBar } from './components/app-bar';\nimport { Avatar } from './components/avatar';\nimport { AvatarGroup } from './components/avatar-group';\nimport { Badge } from './components/badge';\nimport { Breadcrumbs } from './components/breadcrumbs';\nimport { Button } from './components/button';\nimport { ButtonGroup } from './components/button-group';\nimport { Card } from './components/card';\nimport { Checkbox, CheckboxGroup } from './components/checkbox';\nimport { Chip } from './components/chip';\nimport { ChipGroup } from './components/chip-group';\nimport { DataTable } from './components/data-table';\nimport { DatePicker } from './components/date-picker';\nimport { Drawer } from './components/drawer';\nimport { Form, FormActions, FormError, FormField } from './components/form';\nimport { Gradient } from './components/gradient';\nimport { Heading } from './components/heading';\nimport { Icon } from './components/icon';\nimport { IconButton } from './components/icon-button';\nimport { Image } from './components/image';\nimport { Input } from './components/input';\nimport { MediaCard } from './components/media-card';\nimport { DropdownMenu, Menu } from './components/menu';\nimport { MetricCard } from './components/metric-card';\nimport { Modal } from './components/modal';\nimport { NavigationItem } from './components/navigation-item';\nimport { NavigationList } from './components/navigation-list';\nimport { Pagination } from './components/pagination';\nimport { Progress } from './components/progress';\nimport { Radio, RadioGroup } from './components/radio';\nimport { Rating } from './components/rating';\nimport { SearchBar } from './components/search-bar';\nimport { Select } from './components/select';\nimport { Skeleton, SkeletonCard, SkeletonList, SkeletonText } from './components/skeleton';\nimport { SplashScreen } from './components/splash-screen';\nimport { Tabs } from './components/tabs';\nimport { Text } from './components/text';\nimport { Textarea } from './components/textarea';\nimport { TimePicker } from './components/time-picker';\nimport { Toast } from './components/toast';\nimport { Toolbar, ToolbarAction } from './components/toolbar';\nimport {\n Box,\n Center,\n Container,\n Divider,\n Grid,\n Inline,\n Show,\n Spacer,\n Stack,\n Surface,\n} from './foundation';\nimport { AppShell } from './layout/app-shell';\nimport { Screen } from './layout/screen';\nimport { ScreenSection } from './layout/screen-section';\nimport { SettingsLayout } from './layout/settings-layout';\nimport { SidebarLayout } from './layout/sidebar-layout';\nimport { TopbarLayout } from './layout/topbar-layout';\nimport {\n ForgotPasswordForm,\n OAuthProviderButton,\n OAuthProviderList,\n OtpForm,\n SignInForm,\n SignUpForm,\n} from './patterns/auth';\nimport { ChatListItem } from './patterns/chat-list-item';\nimport { CollectionEditor } from './patterns/collection-editor';\nimport { ConfirmDialog } from './patterns/confirm-dialog';\nimport { DisclosureSection } from './patterns/disclosure-section';\nimport { EmptyState } from './patterns/empty-state';\nimport { FilterBar } from './patterns/filter-bar';\nimport { Hero } from './patterns/hero';\nimport { ImagePreview } from './patterns/image-preview';\nimport { ImageUploadField } from './patterns/image-upload-field';\nimport { InspectorField } from './patterns/inspector-field';\nimport { List, ListRow, ListSection } from './patterns/list';\nimport { MessageBubble } from './patterns/message-bubble';\nimport { Notice } from './patterns/notice';\nimport { Panel } from './patterns/panel';\nimport { PostCard } from './patterns/post-card';\nimport { ProductCard } from './patterns/product-card';\nimport { ResponsivePanel } from './patterns/responsive-panel';\nimport { BarcodeScannerView, CameraPermissionView, ScanOverlay } from './patterns/scanner';\nimport { SectionHeader } from './patterns/section-header';\nimport { SelectableItem } from './patterns/selection';\nimport { SettingsRow } from './patterns/settings-row';\nimport { SwitchField } from './patterns/switch-field';\nimport { ThemeComposer } from './patterns/theme-composer';\nimport { PaletteItem, TileGrid } from './patterns/tile-grid';\nimport { Timeline } from './patterns/timeline';\nimport { TreeItem, TreeView } from './patterns/tree-view';\nimport { ZoraDrawerContent } from './patterns/zora-drawer-content';\nimport { ZoraTabBar } from './patterns/zora-tab-bar';\nimport { ThemeModeToggle } from './theme/ThemeModeToggle';\n\nexport type ZoraComponentRegistry = Readonly<Record<string, React.ElementType>>;\n\ntype ComponentPropsFor<K extends keyof typeof _ZORA_COMPONENT_REGISTRY> = React.ComponentProps<\n (typeof _ZORA_COMPONENT_REGISTRY)[K]\n>;\n\ntype AcceptsSurfaceInteractionPolicyProps<P> = 'interactionPolicy' extends keyof P\n ? InteractionPolicyProps extends Pick<P, 'interactionPolicy'>\n ? Pick<P, 'interactionPolicy'> extends InteractionPolicyProps\n ? true\n : false\n : false\n : false;\n\ntype RegistryInteractionPolicyContract = {\n [K in keyof typeof _ZORA_COMPONENT_REGISTRY]: AcceptsSurfaceInteractionPolicyProps<\n ComponentPropsFor<K>\n >;\n};\n\ntype _AssertTrue<T extends true> = T;\ntype _RegistryInteractionPolicyCheck = _AssertTrue<\n RegistryInteractionPolicyContract[keyof typeof _ZORA_COMPONENT_REGISTRY]\n>;\n\nconst _ZORA_COMPONENT_REGISTRY = {\n ActionSheet,\n ActionSheetItem,\n AppBar,\n Avatar,\n AvatarGroup,\n Badge,\n Breadcrumbs,\n Button,\n ButtonGroup,\n Card,\n Checkbox,\n CheckboxGroup,\n Chip,\n ChipGroup,\n DataTable,\n DatePicker,\n Drawer,\n DropdownMenu,\n Form,\n FormActions,\n FormError,\n FormField,\n Gradient,\n Heading,\n Icon,\n IconButton,\n Image,\n Input,\n MediaCard,\n Menu,\n MetricCard,\n Modal,\n NavigationItem,\n NavigationList,\n Pagination,\n Progress,\n Radio,\n RadioGroup,\n Rating,\n SearchBar,\n Select,\n Skeleton,\n SkeletonCard,\n SkeletonList,\n SkeletonText,\n SplashScreen,\n Tabs,\n Text,\n Textarea,\n TimePicker,\n Toast,\n Toolbar,\n ToolbarAction,\n ThemeModeToggle,\n Box,\n Center,\n Container,\n Divider,\n Grid,\n Inline,\n Show,\n Spacer,\n Stack,\n Surface,\n AppShell,\n Screen,\n ScreenSection,\n SettingsLayout,\n SidebarLayout,\n TopbarLayout,\n ForgotPasswordForm,\n OAuthProviderButton,\n OAuthProviderList,\n OtpForm,\n SignInForm,\n SignUpForm,\n ChatListItem,\n CollectionEditor,\n ConfirmDialog,\n DisclosureSection,\n EmptyState,\n FilterBar,\n Hero,\n ImagePreview,\n ImageUploadField,\n InspectorField,\n List,\n ListRow,\n ListSection,\n MessageBubble,\n Notice,\n Panel,\n PostCard,\n ProductCard,\n ResponsivePanel,\n BarcodeScannerView,\n CameraPermissionView,\n ScanOverlay,\n SectionHeader,\n SelectableItem,\n SettingsRow,\n SwitchField,\n ThemeComposer,\n PaletteItem,\n TileGrid,\n Timeline,\n TreeItem,\n TreeView,\n ZoraDrawerContent,\n ZoraTabBar,\n} as const satisfies ZoraComponentRegistry;\n\nexport const ZORA_COMPONENT_REGISTRY: ZoraComponentRegistry = _ZORA_COMPONENT_REGISTRY;\n"]}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InteractionPolicyProps } from '@ankhorage/surface';\nimport type React from 'react';\n\nimport { ActionSheet, ActionSheetItem } from './components/action-sheet';\nimport { AppBar } from './components/app-bar';\nimport { Avatar } from './components/avatar';\nimport { AvatarGroup } from './components/avatar-group';\nimport { Badge } from './components/badge';\nimport { Breadcrumbs } from './components/breadcrumbs';\nimport { Button } from './components/button';\nimport { ButtonGroup } from './components/button-group';\nimport { Card } from './components/card';\nimport { Checkbox, CheckboxGroup } from './components/checkbox';\nimport { Chip } from './components/chip';\nimport { ChipGroup } from './components/chip-group';\nimport { DataTable } from './components/data-table';\nimport { DatePicker } from './components/date-picker';\nimport { Drawer } from './components/drawer';\nimport { Form, FormActions, FormError, FormField } from './components/form';\nimport { Gradient } from './components/gradient';\nimport { Heading } from './components/heading';\nimport { Icon } from './components/icon';\nimport { IconButton } from './components/icon-button';\nimport { Image } from './components/image';\nimport { Input } from './components/input';\nimport { MediaCard } from './components/media-card';\nimport { DropdownMenu, Menu } from './components/menu';\nimport { MetricCard } from './components/metric-card';\nimport { Modal } from './components/modal';\nimport { NavigationItem } from './components/navigation-item';\nimport { NavigationList } from './components/navigation-list';\nimport { Pagination } from './components/pagination';\nimport { Progress } from './components/progress';\nimport { Radio, RadioGroup } from './components/radio';\nimport { Rating } from './components/rating';\nimport { SearchBar } from './components/search-bar';\nimport { Select } from './components/select';\nimport { Skeleton, SkeletonCard, SkeletonList, SkeletonText } from './components/skeleton';\nimport { SplashScreen } from './components/splash-screen';\nimport { Tabs } from './components/tabs';\nimport { Text } from './components/text';\nimport { Textarea } from './components/textarea';\nimport { TimePicker } from './components/time-picker';\nimport { Toast } from './components/toast';\nimport { Toolbar, ToolbarAction } from './components/toolbar';\nimport {\n Box,\n Center,\n Container,\n Divider,\n Grid,\n Inline,\n Show,\n Spacer,\n Stack,\n Surface,\n} from './foundation';\nimport { AppShell } from './layout/app-shell';\nimport { Screen } from './layout/screen';\nimport { ScreenSection } from './layout/screen-section';\nimport { SettingsLayout } from './layout/settings-layout';\nimport { SidebarLayout } from './layout/sidebar-layout';\nimport { TopbarLayout } from './layout/topbar-layout';\nimport {\n ForgotPasswordForm,\n OAuthProviderButton,\n OAuthProviderList,\n OtpForm,\n SignInForm,\n SignUpForm,\n} from './patterns/auth';\nimport { ChatListItem } from './patterns/chat-list-item';\nimport { CollectionEditor } from './patterns/collection-editor';\nimport { ConfirmDialog } from './patterns/confirm-dialog';\nimport { DisclosureSection } from './patterns/disclosure-section';\nimport { EmptyState } from './patterns/empty-state';\nimport { FilterBar } from './patterns/filter-bar';\nimport { Hero } from './patterns/hero';\nimport { ImagePreview } from './patterns/image-preview';\nimport { ImageUploadField } from './patterns/image-upload-field';\nimport { InspectorField } from './patterns/inspector-field';\nimport { List, ListRow, ListSection } from './patterns/list';\nimport { MessageBubble } from './patterns/message-bubble';\nimport { Notice } from './patterns/notice';\nimport { Panel } from './patterns/panel';\nimport { PostCard } from './patterns/post-card';\nimport { ProductCard } from './patterns/product-card';\nimport { ReaderSurface } from './patterns/reader';\nimport { ResponsivePanel } from './patterns/responsive-panel';\nimport { BarcodeScannerView, CameraPermissionView, ScanOverlay } from './patterns/scanner';\nimport { SectionHeader } from './patterns/section-header';\nimport { SelectableItem } from './patterns/selection';\nimport { SettingsRow } from './patterns/settings-row';\nimport { SwitchField } from './patterns/switch-field';\nimport { ThemeComposer } from './patterns/theme-composer';\nimport { PaletteItem, TileGrid } from './patterns/tile-grid';\nimport { Timeline } from './patterns/timeline';\nimport { TreeItem, TreeView } from './patterns/tree-view';\nimport { ZoraDrawerContent } from './patterns/zora-drawer-content';\nimport { ZoraTabBar } from './patterns/zora-tab-bar';\nimport { ThemeModeToggle } from './theme/ThemeModeToggle';\n\nexport type ZoraComponentRegistry = Readonly<Record<string, React.ElementType>>;\n\ntype ComponentPropsFor<K extends keyof typeof _ZORA_COMPONENT_REGISTRY> = React.ComponentProps<\n (typeof _ZORA_COMPONENT_REGISTRY)[K]\n>;\n\ntype AcceptsSurfaceInteractionPolicyProps<P> = 'interactionPolicy' extends keyof P\n ? InteractionPolicyProps extends Pick<P, 'interactionPolicy'>\n ? Pick<P, 'interactionPolicy'> extends InteractionPolicyProps\n ? true\n : false\n : false\n : false;\n\ntype RegistryInteractionPolicyContract = {\n [K in keyof typeof _ZORA_COMPONENT_REGISTRY]: AcceptsSurfaceInteractionPolicyProps<\n ComponentPropsFor<K>\n >;\n};\n\ntype _AssertTrue<T extends true> = T;\ntype _RegistryInteractionPolicyCheck = _AssertTrue<\n RegistryInteractionPolicyContract[keyof typeof _ZORA_COMPONENT_REGISTRY]\n>;\n\nconst _ZORA_COMPONENT_REGISTRY = {\n ActionSheet,\n ActionSheetItem,\n AppBar,\n Avatar,\n AvatarGroup,\n Badge,\n Breadcrumbs,\n Button,\n ButtonGroup,\n Card,\n Checkbox,\n CheckboxGroup,\n Chip,\n ChipGroup,\n DataTable,\n DatePicker,\n Drawer,\n DropdownMenu,\n Form,\n FormActions,\n FormError,\n FormField,\n Gradient,\n Heading,\n Icon,\n IconButton,\n Image,\n Input,\n MediaCard,\n Menu,\n MetricCard,\n Modal,\n NavigationItem,\n NavigationList,\n Pagination,\n Progress,\n Radio,\n RadioGroup,\n Rating,\n SearchBar,\n Select,\n Skeleton,\n SkeletonCard,\n SkeletonList,\n SkeletonText,\n SplashScreen,\n Tabs,\n Text,\n Textarea,\n TimePicker,\n Toast,\n Toolbar,\n ToolbarAction,\n ThemeModeToggle,\n Box,\n Center,\n Container,\n Divider,\n Grid,\n Inline,\n Show,\n Spacer,\n Stack,\n Surface,\n AppShell,\n Screen,\n ScreenSection,\n SettingsLayout,\n SidebarLayout,\n TopbarLayout,\n ForgotPasswordForm,\n OAuthProviderButton,\n OAuthProviderList,\n OtpForm,\n SignInForm,\n SignUpForm,\n ChatListItem,\n CollectionEditor,\n ConfirmDialog,\n DisclosureSection,\n EmptyState,\n FilterBar,\n Hero,\n ImagePreview,\n ImageUploadField,\n InspectorField,\n List,\n ListRow,\n ListSection,\n MessageBubble,\n Notice,\n Panel,\n PostCard,\n ProductCard,\n ResponsivePanel,\n ReaderSurface,\n BarcodeScannerView,\n CameraPermissionView,\n ScanOverlay,\n SectionHeader,\n SelectableItem,\n SettingsRow,\n SwitchField,\n ThemeComposer,\n PaletteItem,\n TileGrid,\n Timeline,\n TreeItem,\n TreeView,\n ZoraDrawerContent,\n ZoraTabBar,\n} as const satisfies ZoraComponentRegistry;\n\nexport const ZORA_COMPONENT_REGISTRY: ZoraComponentRegistry = _ZORA_COMPONENT_REGISTRY;\n"]}
@@ -1,7 +1,7 @@
1
1
  export declare function useZoraTheme(): {
2
2
  theme: import("@ankhorage/surface").SurfaceTheme;
3
3
  mode: "light" | "dark";
4
- setThemeConfig: (config: Partial<import("@ankhorage/contracts").ThemeConfig>) => void;
4
+ setThemeConfig: (config: Partial<import("@ankhorage/surface").ThemeConfig>) => void;
5
5
  setMode: (mode: "light" | "dark") => void;
6
6
  _hasProvider?: boolean;
7
7
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ankhorage/zora",
3
3
  "type": "module",
4
- "version": "3.0.2",
4
+ "version": "3.1.0",
5
5
  "description": "Opinionated React Native and React Native Web UI kit built on @ankhorage/surface.",
6
6
  "homepage": "https://github.com/ankhorage/zora#readme",
7
7
  "bugs": {
@@ -37,7 +37,7 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "@ankhorage/color-theory": "^0.0.8",
40
- "@ankhorage/contracts": "^8.0.0",
40
+ "@ankhorage/contracts": "^8.0.1",
41
41
  "@ankhorage/surface": "^3.0.2"
42
42
  },
43
43
  "files": [
@@ -86,7 +86,7 @@
86
86
  "version-packages": "ankhorage-changeset version"
87
87
  },
88
88
  "devDependencies": {
89
- "@ankhorage/devtools": "^1.8.2",
89
+ "@ankhorage/devtools": "^1.8.3",
90
90
  "@ankhorage/paradox": "^0.1.24",
91
91
  "@react-native-picker/picker": "2.11.4",
92
92
  "@react-native-vector-icons/fontawesome": "^13.1.3",
@@ -56,6 +56,7 @@ function TextInner({
56
56
  accessibilityLabel,
57
57
  accessibilityHint,
58
58
  accessibilityRole,
59
+ accessibilityLiveRegion,
59
60
  nativeID,
60
61
  testID,
61
62
  interactionPolicy: _interactionPolicy,
@@ -82,6 +83,7 @@ function TextInner({
82
83
  <ReactNativeText
83
84
  accessibilityHint={accessibilityHint}
84
85
  accessibilityLabel={accessibilityLabel}
86
+ accessibilityLiveRegion={accessibilityLiveRegion}
85
87
  accessibilityRole={accessibilityRole}
86
88
  ellipsizeMode={ellipsizeMode}
87
89
  nativeID={nativeID}
@@ -1,6 +1,11 @@
1
1
  import type { Responsive } from '@ankhorage/surface';
2
2
  import type React from 'react';
3
- import type { AccessibilityRole, StyleProp, TextStyle } from 'react-native';
3
+ import type {
4
+ AccessibilityRole,
5
+ StyleProp,
6
+ TextProps as ReactNativeTextProps,
7
+ TextStyle,
8
+ } from 'react-native';
4
9
 
5
10
  import type { ZoraColor, ZoraEmphasis } from '../../internal/recipes';
6
11
  import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
@@ -31,5 +36,6 @@ export interface TextProps extends ZoraBaseProps {
31
36
  accessibilityLabel?: string;
32
37
  accessibilityHint?: string;
33
38
  accessibilityRole?: AccessibilityRole;
39
+ accessibilityLiveRegion?: ReactNativeTextProps['accessibilityLiveRegion'];
34
40
  nativeID?: string;
35
41
  }
@@ -20,6 +20,10 @@ const RNVI_PLUGINS = [
20
20
  '@react-native-vector-icons/fontawesome6',
21
21
  '@react-native-vector-icons/ionicons',
22
22
  ] as const;
23
+ const CARET_SEMVER_RANGE = /^\^\d+\.\d+\.\d+$/u;
24
+ const EXACT_SEMVER_VERSION = /^\d+\.\d+\.\d+$/u;
25
+ const MINOR_WILDCARD_SEMVER_RANGE = /^\d+\.\d+\.x$/u;
26
+ const TILDE_SEMVER_RANGE = /^~\d+\.\d+\.\d+$/u;
23
27
 
24
28
  function readJson(path: string): Record<string, unknown> {
25
29
  const value: unknown = JSON.parse(readFileSync(path, 'utf8'));
@@ -46,18 +50,18 @@ function readExamplePackage(directory: string): Record<string, unknown> {
46
50
  }
47
51
 
48
52
  describe('portable ZORA package boundary', () => {
49
- test('targets the released RN 0.86 and Surface 3 contract without Expo runtime peers', () => {
53
+ test('uses the expected dependency range styles without Expo runtime peers', () => {
50
54
  const packageJson = readJson(join(ROOT, 'package.json'));
51
55
  const dependencies = readRecord(packageJson, 'dependencies');
52
56
  const peers = readRecord(packageJson, 'peerDependencies');
53
57
  const development = readRecord(packageJson, 'devDependencies');
54
58
 
55
- expect(readValue(dependencies, '@ankhorage/surface')).toBe('^3.0.2');
56
- expect(readValue(dependencies, '@ankhorage/contracts')).toBe('^8.0.0');
57
- expect(peers.react).toBe('19.2.3');
58
- expect(readValue(peers, 'react-native')).toBe('0.86.x');
59
- expect(readValue(peers, 'react-native-web')).toBe('~0.21.0');
60
- expect(development.typescript).toBe('~6.0.3');
59
+ expect(readValue(dependencies, '@ankhorage/surface')).toMatch(CARET_SEMVER_RANGE);
60
+ expect(readValue(dependencies, '@ankhorage/contracts')).toMatch(CARET_SEMVER_RANGE);
61
+ expect(peers.react).toMatch(EXACT_SEMVER_VERSION);
62
+ expect(readValue(peers, 'react-native')).toMatch(MINOR_WILDCARD_SEMVER_RANGE);
63
+ expect(readValue(peers, 'react-native-web')).toMatch(TILDE_SEMVER_RANGE);
64
+ expect(development.typescript).toMatch(TILDE_SEMVER_RANGE);
61
65
 
62
66
  for (const expoPackage of ['@expo/vector-icons', 'expo-font', 'expo-linear-gradient']) {
63
67
  expect(readValue(peers, expoPackage)).toBeUndefined();
@@ -82,18 +86,18 @@ describe('portable ZORA package boundary', () => {
82
86
  });
83
87
 
84
88
  describe('Expo 57 example boundary', () => {
85
- test('uses the canonical React, RN, RNW, TypeScript, and Expo baselines', () => {
89
+ test('uses Renovate-safe dependency range styles across every Expo example', () => {
86
90
  for (const directory of EXPO_EXAMPLE_DIRS) {
87
91
  const packageJson = readExamplePackage(directory);
88
92
  const dependencies = readRecord(packageJson, 'dependencies');
89
93
  const development = readRecord(packageJson, 'devDependencies');
90
94
 
91
- expect(readValue(dependencies, '@ankhorage/zora')).toBe('^3.0.0');
92
- expect(dependencies.expo).toBe('57.0.18');
93
- expect(dependencies.react).toBe('19.2.3');
94
- expect(readValue(dependencies, 'react-native')).toBe('0.86.3');
95
- expect(readValue(dependencies, 'react-native-web')).toBe('~0.21.0');
96
- expect(development.typescript).toBe('~6.0.3');
95
+ expect(readValue(dependencies, '@ankhorage/zora')).toMatch(CARET_SEMVER_RANGE);
96
+ expect(dependencies.expo).toMatch(EXACT_SEMVER_VERSION);
97
+ expect(dependencies.react).toMatch(EXACT_SEMVER_VERSION);
98
+ expect(readValue(dependencies, 'react-native')).toMatch(EXACT_SEMVER_VERSION);
99
+ expect(readValue(dependencies, 'react-native-web')).toMatch(TILDE_SEMVER_RANGE);
100
+ expect(development.typescript).toMatch(TILDE_SEMVER_RANGE);
97
101
  expect(readValue(dependencies, '@expo/vector-icons')).toBeUndefined();
98
102
  }
99
103
  });
package/src/index.ts CHANGED
@@ -327,6 +327,20 @@ export type {
327
327
  export { PostCard } from './patterns/post-card';
328
328
  export type { ProductCardProps } from './patterns/product-card';
329
329
  export { ProductCard } from './patterns/product-card';
330
+ export type {
331
+ ReaderColorScheme,
332
+ ReaderDocumentFormat,
333
+ ReaderErrorCode,
334
+ ReaderErrorEvent,
335
+ ReaderExternalLinkEvent,
336
+ ReaderLineHeight,
337
+ ReaderLocationChangeEvent,
338
+ ReaderNavigationTrigger,
339
+ ReaderResolvedSource,
340
+ ReaderStatus,
341
+ ReaderSurfaceProps,
342
+ } from './patterns/reader';
343
+ export { ReaderSurface, resolveReaderProgress } from './patterns/reader';
330
344
  export type {
331
345
  ResponsivePanelDesktopMode,
332
346
  ResponsivePanelMobileMode,
@@ -42,6 +42,7 @@ describe('InteractionPolicy declaration', () => {
42
42
  readPattern('empty-state', 'types.ts'),
43
43
  readPattern('hero', 'types.ts'),
44
44
  readPattern('product-card', 'types.ts'),
45
+ readPattern('reader', 'types.ts'),
45
46
  readPattern('scanner', 'types.ts'),
46
47
  readPattern('zora-tab-bar', 'types.ts'),
47
48
  readComponent('select', 'types.ts'),
@@ -156,6 +157,35 @@ describe('ProductCard', () => {
156
157
  });
157
158
  });
158
159
 
160
+ describe('ReaderSurface', () => {
161
+ test('types extend ZoraBaseProps instead of duplicating InteractionPolicy', () => {
162
+ const source = readPattern('reader', 'types.ts');
163
+
164
+ expect(source).not.toMatch(
165
+ /import type \{\s*InteractionPolicy\s*\} from '@ankhorage\/surface';/,
166
+ );
167
+ expect(source).toMatch(/export interface ReaderSurfaceProps extends ZoraBaseProps/);
168
+ expect(source).not.toMatch(/interactionPolicy\?: InteractionPolicy;/);
169
+ });
170
+
171
+ test('forwards interactionPolicy to its owned interactive controls', () => {
172
+ const source = readPattern('reader', 'ReaderSurface.tsx');
173
+
174
+ expect(source).not.toMatch(/interactionPolicy:\s*_interactionPolicy/);
175
+ expect(source).toMatch(
176
+ /function ReaderHeader[\s\S]*?<IconButton[\s\S]*?interactionPolicy=\{interactionPolicy\}/,
177
+ );
178
+ expect(source).toMatch(
179
+ /function ReaderHeader[\s\S]*?<AppBar[\s\S]*?interactionPolicy=\{interactionPolicy\}/,
180
+ );
181
+ expect(source).toMatch(
182
+ /function ReaderFooter[\s\S]*?<IconButton[\s\S]*?interactionPolicy=\{interactionPolicy\}/,
183
+ );
184
+ expect(source).toMatch(/<ReaderHeader[\s\S]*?interactionPolicy=\{interactionPolicy\}/);
185
+ expect(source).toMatch(/<ReaderFooter[\s\S]*?interactionPolicy=\{interactionPolicy\}/);
186
+ });
187
+ });
188
+
159
189
  describe('CameraPermissionView', () => {
160
190
  test('forwards interactionPolicy to internal Buttons after prop spreads', () => {
161
191
  const source = readPattern('scanner', 'CameraPermissionView.tsx');
@@ -21,6 +21,7 @@ export const CONTAINER_ALLOWED_CHILDREN = [
21
21
  'PostCard',
22
22
  'ChatListItem',
23
23
  'MessageBubble',
24
+ 'ReaderSurface',
24
25
  ] as const;
25
26
 
26
27
  export const SCREEN_SECTION_ALLOWED_CHILDREN = [...CONTAINER_ALLOWED_CHILDREN] as const;
@@ -28,4 +28,34 @@ describe('ZORA bindable component metadata', () => {
28
28
  expect(image.directManifestNode).toBe(ZORA_COMPONENT_META.Image.directManifestNode);
29
29
  expect(image.bindings.props.source.value.type).toBe('imageAsset');
30
30
  });
31
+
32
+ it('describes serializable controlled ReaderSurface bindings', () => {
33
+ const reader = ZORA_BINDABLE_COMPONENT_META.ReaderSurface;
34
+
35
+ expect(Object.keys(reader.bindings.props)).toEqual([
36
+ 'location',
37
+ 'page',
38
+ 'pageCount',
39
+ 'progress',
40
+ 'status',
41
+ ]);
42
+ expect(reader.bindings.events.locationChange.payload.fields.map((field) => field.path)).toEqual(
43
+ [
44
+ 'format',
45
+ 'locator',
46
+ 'page',
47
+ 'pageCount',
48
+ 'progression',
49
+ 'chapterId',
50
+ 'chapterTitle',
51
+ 'trigger',
52
+ ],
53
+ );
54
+ expect(reader.bindings.events.openExternalLink.payload.fields).toEqual([
55
+ { path: 'url', type: 'string', label: 'URL' },
56
+ ]);
57
+ expect(reader.bindings.props.location.value.type).toBe('string');
58
+ expect(reader.bindings.props.page.value.type).toBe('number');
59
+ expect(reader.bindings.events.locationChange.payload.eventType).toBe('reader.locationChange');
60
+ });
31
61
  });
@@ -1,6 +1,7 @@
1
1
  import type { UiComponentMetaRegistry } from '@ankhorage/contracts';
2
2
 
3
3
  import { imageMeta } from '../components/image/meta';
4
+ import { readerSurfaceMeta } from '../patterns/reader/meta';
4
5
 
5
6
  export const ZORA_BINDABLE_COMPONENT_META = {
6
7
  Text: {
@@ -462,6 +463,107 @@ export const ZORA_BINDABLE_COMPONENT_META = {
462
463
  },
463
464
  },
464
465
  },
466
+ ReaderSurface: {
467
+ ...readerSurfaceMeta,
468
+ bindings: {
469
+ props: {
470
+ location: {
471
+ label: 'Location',
472
+ description: 'Opaque adapter locator to restore.',
473
+ value: { type: 'string' },
474
+ acceptsFallback: true,
475
+ acceptsTransforms: true,
476
+ },
477
+ page: {
478
+ label: 'Page',
479
+ description: 'One-based visible page.',
480
+ value: { type: 'number' },
481
+ acceptsFallback: true,
482
+ acceptsTransforms: true,
483
+ },
484
+ pageCount: {
485
+ label: 'Page count',
486
+ description: 'Current number of logical pages.',
487
+ value: { type: 'number' },
488
+ acceptsFallback: true,
489
+ acceptsTransforms: true,
490
+ },
491
+ progress: {
492
+ label: 'Progress',
493
+ description: 'Reading progression clamped from zero to one.',
494
+ value: { type: 'number' },
495
+ acceptsFallback: true,
496
+ acceptsTransforms: true,
497
+ },
498
+ status: {
499
+ label: 'Status',
500
+ description: 'Current reader loading status.',
501
+ value: { type: 'string' },
502
+ acceptsFallback: true,
503
+ acceptsTransforms: true,
504
+ },
505
+ },
506
+ events: {
507
+ previousPage: {
508
+ label: 'Previous page',
509
+ description: 'Requests navigation to the previous page.',
510
+ payload: { eventType: 'reader.previousPage', fields: [] },
511
+ },
512
+ nextPage: {
513
+ label: 'Next page',
514
+ description: 'Requests navigation to the next page.',
515
+ payload: { eventType: 'reader.nextPage', fields: [] },
516
+ },
517
+ locationChange: {
518
+ label: 'Location change',
519
+ description: 'Runs after the adapter displays a destination.',
520
+ payload: {
521
+ eventType: 'reader.locationChange',
522
+ fields: [
523
+ { path: 'format', type: 'string', label: 'Format' },
524
+ { path: 'locator', type: 'string', label: 'Opaque locator' },
525
+ { path: 'page', type: 'number', label: 'Page' },
526
+ { path: 'pageCount', type: 'number', label: 'Page count' },
527
+ { path: 'progression', type: 'number', label: 'Progression' },
528
+ { path: 'chapterId', type: 'string', label: 'Chapter ID' },
529
+ { path: 'chapterTitle', type: 'string', label: 'Chapter title' },
530
+ { path: 'trigger', type: 'string', label: 'Navigation trigger' },
531
+ ],
532
+ },
533
+ },
534
+ openContents: {
535
+ label: 'Open contents',
536
+ payload: { eventType: 'reader.openContents', fields: [] },
537
+ },
538
+ openAppearance: {
539
+ label: 'Open appearance',
540
+ payload: { eventType: 'reader.openAppearance', fields: [] },
541
+ },
542
+ toggleHighlight: {
543
+ label: 'Toggle highlight',
544
+ payload: { eventType: 'reader.toggleHighlight', fields: [] },
545
+ },
546
+ openExternalLink: {
547
+ label: 'Open external link',
548
+ payload: {
549
+ eventType: 'reader.openExternalLink',
550
+ fields: [{ path: 'url', type: 'string', label: 'URL' }],
551
+ },
552
+ },
553
+ readerError: {
554
+ label: 'Reader error',
555
+ payload: {
556
+ eventType: 'reader.error',
557
+ fields: [
558
+ { path: 'code', type: 'string', label: 'Error code' },
559
+ { path: 'format', type: 'string', label: 'Format' },
560
+ { path: 'message', type: 'string', label: 'Message' },
561
+ ],
562
+ },
563
+ },
564
+ },
565
+ },
566
+ },
465
567
  } as const satisfies UiComponentMetaRegistry;
466
568
 
467
569
  export type ZoraBindableComponentType = keyof typeof ZORA_BINDABLE_COMPONENT_META;
@@ -88,6 +88,12 @@ describe('ZORA_COMPONENT_META requirement metadata', () => {
88
88
  });
89
89
  });
90
90
 
91
+ test('declares ebook reader capability metadata for ReaderSurface', () => {
92
+ expect(ZORA_COMPONENT_META.ReaderSurface.requirements).toEqual({
93
+ capabilities: [{ capability: 'ebookReader' }],
94
+ });
95
+ });
96
+
91
97
  test('does not declare runtime requirements for the camera-agnostic scan overlay', () => {
92
98
  expect(ZORA_COMPONENT_META.ScanOverlay.requirements).toBeUndefined();
93
99
  });
@@ -132,6 +138,7 @@ describe('ZORA_COMPONENT_META invariants', () => {
132
138
  'ScanOverlay',
133
139
  'ProductCard',
134
140
  'Progress',
141
+ 'ReaderSurface',
135
142
  ]);
136
143
 
137
144
  const expectedContainerNodes = new Set([
@@ -204,6 +211,35 @@ describe('ZORA_COMPONENT_META invariants', () => {
204
211
  });
205
212
  });
206
213
 
214
+ test('ReaderSurface exposes a safe file-media blueprint and normalized events', () => {
215
+ const reader = ZORA_COMPONENT_META.ReaderSurface;
216
+
217
+ expect(reader.directManifestNode).toBe(true);
218
+ expect(reader.allowedChildren).toEqual([]);
219
+ expect(reader.props.source).toMatchObject({ type: 'media', mediaKinds: ['file'] });
220
+ expect(reader.props.format.enum).toEqual(['epub', 'pdf']);
221
+ expect(reader.blueprint?.defaultProps).toEqual({
222
+ format: 'epub',
223
+ status: 'idle',
224
+ showChrome: true,
225
+ readerColorScheme: 'system',
226
+ fontScale: 1,
227
+ lineHeight: 'normal',
228
+ });
229
+ expect(reader.blueprint?.defaultProps).not.toHaveProperty('source');
230
+ expect(reader.events?.locationChange?.payloadFields?.map((field) => field.path)).toEqual([
231
+ 'format',
232
+ 'locator',
233
+ 'page',
234
+ 'pageCount',
235
+ 'progression',
236
+ 'chapterId',
237
+ 'chapterTitle',
238
+ 'trigger',
239
+ ]);
240
+ expect(reader.events?.readerError?.eventType).toBe('reader.error');
241
+ });
242
+
207
243
  test('non-direct manifest nodes include an explicit note', () => {
208
244
  for (const [key, meta] of Object.entries(ZORA_COMPONENT_META)) {
209
245
  if (meta.directManifestNode) continue;