@ankhorage/zora 3.1.1 → 3.3.1

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 (105) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +1 -1
  3. package/dist/components/card/meta.d.ts +1 -1
  4. package/dist/components/progress/ProgressRing.d.ts +7 -0
  5. package/dist/components/progress/ProgressRing.d.ts.map +1 -0
  6. package/dist/components/progress/ProgressRing.js +100 -0
  7. package/dist/components/progress/ProgressRing.js.map +1 -0
  8. package/dist/components/progress/index.d.ts +2 -1
  9. package/dist/components/progress/index.d.ts.map +1 -1
  10. package/dist/components/progress/index.js +1 -0
  11. package/dist/components/progress/index.js.map +1 -1
  12. package/dist/components/progress/meta.d.ts +116 -0
  13. package/dist/components/progress/meta.d.ts.map +1 -1
  14. package/dist/components/progress/meta.js +97 -0
  15. package/dist/components/progress/meta.js.map +1 -1
  16. package/dist/components/progress/resolveProgressRingGeometry.d.ts +12 -0
  17. package/dist/components/progress/resolveProgressRingGeometry.d.ts.map +1 -0
  18. package/dist/components/progress/resolveProgressRingGeometry.js +27 -0
  19. package/dist/components/progress/resolveProgressRingGeometry.js.map +1 -0
  20. package/dist/components/progress/types.d.ts +12 -0
  21. package/dist/components/progress/types.d.ts.map +1 -1
  22. package/dist/components/progress/types.js.map +1 -1
  23. package/dist/foundation/meta.d.ts +4 -4
  24. package/dist/index.d.ts +4 -2
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +2 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/layout/screen/meta.d.ts +1 -1
  29. package/dist/layout/screen-section/meta.d.ts +1 -1
  30. package/dist/metadata/allowedChildren.d.ts +4 -3
  31. package/dist/metadata/allowedChildren.d.ts.map +1 -1
  32. package/dist/metadata/allowedChildren.js +13 -0
  33. package/dist/metadata/allowedChildren.js.map +1 -1
  34. package/dist/metadata/bindableComponentMeta.d.ts +2 -2
  35. package/dist/metadata/componentMeta.d.ts.map +1 -1
  36. package/dist/metadata/componentMeta.js +4 -1
  37. package/dist/metadata/componentMeta.js.map +1 -1
  38. package/dist/patterns/content-rail/ContentRail.d.ts +10 -0
  39. package/dist/patterns/content-rail/ContentRail.d.ts.map +1 -0
  40. package/dist/patterns/content-rail/ContentRail.js +175 -0
  41. package/dist/patterns/content-rail/ContentRail.js.map +1 -0
  42. package/dist/patterns/content-rail/index.d.ts +3 -0
  43. package/dist/patterns/content-rail/index.d.ts.map +1 -0
  44. package/dist/patterns/content-rail/index.js +2 -0
  45. package/dist/patterns/content-rail/index.js.map +1 -0
  46. package/dist/patterns/content-rail/meta.d.ts +143 -0
  47. package/dist/patterns/content-rail/meta.d.ts.map +1 -0
  48. package/dist/patterns/content-rail/meta.js +130 -0
  49. package/dist/patterns/content-rail/meta.js.map +1 -0
  50. package/dist/patterns/content-rail/resolveContentRailItemWidth.d.ts +10 -0
  51. package/dist/patterns/content-rail/resolveContentRailItemWidth.d.ts.map +1 -0
  52. package/dist/patterns/content-rail/resolveContentRailItemWidth.js +25 -0
  53. package/dist/patterns/content-rail/resolveContentRailItemWidth.js.map +1 -0
  54. package/dist/patterns/content-rail/resolveContentRailPhysicalOffset.d.ts +6 -0
  55. package/dist/patterns/content-rail/resolveContentRailPhysicalOffset.d.ts.map +1 -0
  56. package/dist/patterns/content-rail/resolveContentRailPhysicalOffset.js +5 -0
  57. package/dist/patterns/content-rail/resolveContentRailPhysicalOffset.js.map +1 -0
  58. package/dist/patterns/content-rail/resolveContentRailState.d.ts +18 -0
  59. package/dist/patterns/content-rail/resolveContentRailState.d.ts.map +1 -0
  60. package/dist/patterns/content-rail/resolveContentRailState.js +21 -0
  61. package/dist/patterns/content-rail/resolveContentRailState.js.map +1 -0
  62. package/dist/patterns/content-rail/types.d.ts +31 -0
  63. package/dist/patterns/content-rail/types.d.ts.map +1 -0
  64. package/dist/patterns/content-rail/types.js +2 -0
  65. package/dist/patterns/content-rail/types.js.map +1 -0
  66. package/dist/patterns/content-rail/useContentRailReducedMotion.d.ts +3 -0
  67. package/dist/patterns/content-rail/useContentRailReducedMotion.d.ts.map +1 -0
  68. package/dist/patterns/content-rail/useContentRailReducedMotion.js +21 -0
  69. package/dist/patterns/content-rail/useContentRailReducedMotion.js.map +1 -0
  70. package/dist/patterns/message-bubble/meta.d.ts +1 -1
  71. package/dist/patterns/notice/meta.d.ts +1 -1
  72. package/dist/patterns/panel/meta.d.ts +1 -1
  73. package/dist/patterns/post-card/meta.d.ts +1 -1
  74. package/dist/patterns/reader/meta.d.ts +2 -2
  75. package/dist/patterns/scanner/meta.d.ts +2 -2
  76. package/dist/registry.d.ts.map +1 -1
  77. package/dist/registry.js +4 -1
  78. package/dist/registry.js.map +1 -1
  79. package/package.json +2 -2
  80. package/src/components/progress/ProgressRing.test.ts +48 -0
  81. package/src/components/progress/ProgressRing.tsx +151 -0
  82. package/src/components/progress/index.ts +2 -1
  83. package/src/components/progress/meta.ts +99 -0
  84. package/src/components/progress/resolveProgressRingGeometry.test.ts +30 -0
  85. package/src/components/progress/resolveProgressRingGeometry.ts +44 -0
  86. package/src/components/progress/types.ts +13 -0
  87. package/src/index.ts +12 -2
  88. package/src/interactionPolicy.test.ts +22 -0
  89. package/src/metadata/allowedChildren.ts +14 -0
  90. package/src/metadata/componentMeta.test.ts +51 -0
  91. package/src/metadata/componentMeta.ts +4 -1
  92. package/src/patterns/content-rail/ContentRail.test.ts +44 -0
  93. package/src/patterns/content-rail/ContentRail.tsx +245 -0
  94. package/src/patterns/content-rail/index.ts +10 -0
  95. package/src/patterns/content-rail/meta.ts +133 -0
  96. package/src/patterns/content-rail/resolveContentRailItemWidth.test.ts +77 -0
  97. package/src/patterns/content-rail/resolveContentRailItemWidth.ts +39 -0
  98. package/src/patterns/content-rail/resolveContentRailPhysicalOffset.test.ts +29 -0
  99. package/src/patterns/content-rail/resolveContentRailPhysicalOffset.ts +12 -0
  100. package/src/patterns/content-rail/resolveContentRailState.test.ts +68 -0
  101. package/src/patterns/content-rail/resolveContentRailState.ts +36 -0
  102. package/src/patterns/content-rail/types.ts +35 -0
  103. package/src/patterns/content-rail/useContentRailReducedMotion.ts +28 -0
  104. package/src/registry.ts +4 -1
  105. package/src/showcaseCoverage.test.ts +1 -0
@@ -0,0 +1,12 @@
1
+ export function resolveContentRailPhysicalOffset({
2
+ isRtl,
3
+ logicalOffset,
4
+ maxOffset,
5
+ }: {
6
+ isRtl: boolean;
7
+ logicalOffset: number;
8
+ maxOffset: number;
9
+ }): number {
10
+ const clampedOffset = Math.min(Math.max(0, logicalOffset), Math.max(0, maxOffset));
11
+ return isRtl ? Math.max(0, maxOffset) - clampedOffset : clampedOffset;
12
+ }
@@ -0,0 +1,68 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+
3
+ import { resolveContentRailState } from './resolveContentRailState';
4
+
5
+ describe('resolveContentRailState', () => {
6
+ test('resolves overflow, visible items, and the nearest navigation anchor', () => {
7
+ expect(
8
+ resolveContentRailState({
9
+ contentWidth: 848,
10
+ gap: 16,
11
+ itemCount: 4,
12
+ itemWidth: 200,
13
+ logicalOffset: 216,
14
+ viewportWidth: 432,
15
+ }),
16
+ ).toEqual({
17
+ anchorIndex: 1,
18
+ canGoNext: true,
19
+ canGoPrevious: true,
20
+ firstVisibleIndex: 1,
21
+ lastVisibleIndex: 2,
22
+ maxOffset: 416,
23
+ offset: 216,
24
+ stride: 216,
25
+ });
26
+ });
27
+
28
+ test('clamps boundaries without wrapping', () => {
29
+ const start = resolveContentRailState({
30
+ contentWidth: 848,
31
+ gap: 16,
32
+ itemCount: 4,
33
+ itemWidth: 200,
34
+ logicalOffset: -100,
35
+ viewportWidth: 432,
36
+ });
37
+ const end = resolveContentRailState({
38
+ contentWidth: 848,
39
+ gap: 16,
40
+ itemCount: 4,
41
+ itemWidth: 200,
42
+ logicalOffset: 1000,
43
+ viewportWidth: 432,
44
+ });
45
+
46
+ expect(start).toMatchObject({ offset: 0, canGoPrevious: false, canGoNext: true });
47
+ expect(end).toMatchObject({ offset: 416, canGoPrevious: true, canGoNext: false });
48
+ });
49
+
50
+ test('degrades to a non-overflowing empty range', () => {
51
+ expect(
52
+ resolveContentRailState({
53
+ contentWidth: 0,
54
+ gap: 16,
55
+ itemCount: 0,
56
+ itemWidth: 0,
57
+ logicalOffset: 0,
58
+ viewportWidth: 432,
59
+ }),
60
+ ).toMatchObject({
61
+ canGoNext: false,
62
+ canGoPrevious: false,
63
+ firstVisibleIndex: -1,
64
+ lastVisibleIndex: -1,
65
+ maxOffset: 0,
66
+ });
67
+ });
68
+ });
@@ -0,0 +1,36 @@
1
+ export function resolveContentRailState({
2
+ contentWidth,
3
+ gap,
4
+ itemCount,
5
+ itemWidth,
6
+ logicalOffset,
7
+ viewportWidth,
8
+ }: {
9
+ contentWidth: number;
10
+ gap: number;
11
+ itemCount: number;
12
+ itemWidth: number;
13
+ logicalOffset: number;
14
+ viewportWidth: number;
15
+ }) {
16
+ const maxOffset = Math.max(0, contentWidth - viewportWidth);
17
+ const offset = Math.min(Math.max(0, logicalOffset), maxOffset);
18
+ const stride = itemWidth + gap;
19
+ const firstVisibleIndex = stride > 0 ? Math.min(itemCount - 1, Math.floor(offset / stride)) : 0;
20
+ const lastVisibleIndex =
21
+ stride > 0
22
+ ? Math.min(itemCount - 1, Math.max(0, Math.ceil((offset + viewportWidth) / stride) - 1))
23
+ : 0;
24
+ const anchorIndex = stride > 0 ? Math.round(offset / stride) : 0;
25
+
26
+ return {
27
+ anchorIndex: Math.min(Math.max(0, anchorIndex), Math.max(0, itemCount - 1)),
28
+ canGoNext: itemCount > 0 && offset < maxOffset - 1,
29
+ canGoPrevious: itemCount > 0 && offset > 1,
30
+ firstVisibleIndex: itemCount === 0 ? -1 : firstVisibleIndex,
31
+ lastVisibleIndex: itemCount === 0 ? -1 : lastVisibleIndex,
32
+ maxOffset,
33
+ offset,
34
+ stride,
35
+ };
36
+ }
@@ -0,0 +1,35 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
4
+
5
+ export type ContentRailDirection = 'auto' | 'ltr' | 'rtl';
6
+ export type ContentRailItemSize = 'compact' | 'regular' | 'wide' | 'responsive';
7
+ export type ContentRailMotion = 'system' | 'animated' | 'reduced';
8
+ export type ContentRailSpacing = 'none' | 'xs' | 's' | 'm' | 'l' | 'xl';
9
+
10
+ export interface ContentRailControlPressEvent {
11
+ direction: 'previous' | 'next';
12
+ targetIndex: number;
13
+ }
14
+
15
+ export interface ContentRailVisibleRangeChangeEvent {
16
+ firstVisibleIndex: number;
17
+ lastVisibleIndex: number;
18
+ itemCount: number;
19
+ }
20
+
21
+ export interface ContentRailProps extends ZoraBaseProps {
22
+ children?: ReactNode;
23
+ itemSize?: ContentRailItemSize;
24
+ gap?: ContentRailSpacing;
25
+ padding?: ContentRailSpacing;
26
+ peek?: number;
27
+ showControls?: boolean;
28
+ direction?: ContentRailDirection;
29
+ motion?: ContentRailMotion;
30
+ accessibilityLabel?: string;
31
+ previousLabel?: string;
32
+ nextLabel?: string;
33
+ onControlPress?: (event: ContentRailControlPressEvent) => void | Promise<void>;
34
+ onVisibleRangeChange?: (event: ContentRailVisibleRangeChangeEvent) => void | Promise<void>;
35
+ }
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { AccessibilityInfo } from 'react-native';
3
+
4
+ import type { ContentRailMotion } from './types';
5
+
6
+ export function useContentRailReducedMotion(motion: ContentRailMotion): boolean {
7
+ const [systemReducedMotion, setSystemReducedMotion] = React.useState(false);
8
+
9
+ React.useEffect(() => {
10
+ if (motion !== 'system') return;
11
+
12
+ let active = true;
13
+ void AccessibilityInfo.isReduceMotionEnabled().then((enabled) => {
14
+ if (active) setSystemReducedMotion(enabled);
15
+ });
16
+ const subscription = AccessibilityInfo.addEventListener(
17
+ 'reduceMotionChanged',
18
+ setSystemReducedMotion,
19
+ );
20
+
21
+ return () => {
22
+ active = false;
23
+ subscription.remove();
24
+ };
25
+ }, [motion]);
26
+
27
+ return motion === 'reduced' || (motion === 'system' && systemReducedMotion);
28
+ }
package/src/registry.ts CHANGED
@@ -30,7 +30,7 @@ import { Modal } from './components/modal';
30
30
  import { NavigationItem } from './components/navigation-item';
31
31
  import { NavigationList } from './components/navigation-list';
32
32
  import { Pagination } from './components/pagination';
33
- import { Progress } from './components/progress';
33
+ import { Progress, ProgressRing } from './components/progress';
34
34
  import { Radio, RadioGroup } from './components/radio';
35
35
  import { Rating } from './components/rating';
36
36
  import { SearchBar } from './components/search-bar';
@@ -72,6 +72,7 @@ import {
72
72
  import { ChatListItem } from './patterns/chat-list-item';
73
73
  import { CollectionEditor } from './patterns/collection-editor';
74
74
  import { ConfirmDialog } from './patterns/confirm-dialog';
75
+ import { ContentRail } from './patterns/content-rail';
75
76
  import { DisclosureSection } from './patterns/disclosure-section';
76
77
  import { EmptyState } from './patterns/empty-state';
77
78
  import { FilterBar } from './patterns/filter-bar';
@@ -162,6 +163,7 @@ const _ZORA_COMPONENT_REGISTRY = {
162
163
  NavigationList,
163
164
  Pagination,
164
165
  Progress,
166
+ ProgressRing,
165
167
  Radio,
166
168
  RadioGroup,
167
169
  Rating,
@@ -205,6 +207,7 @@ const _ZORA_COMPONENT_REGISTRY = {
205
207
  ChatListItem,
206
208
  CollectionEditor,
207
209
  ConfirmDialog,
210
+ ContentRail,
208
211
  DisclosureSection,
209
212
  EmptyState,
210
213
  FilterBar,
@@ -44,6 +44,7 @@ const REQUIRED_SHOWCASE_COVERAGE = {
44
44
  'NavigationItem',
45
45
  'NavigationList',
46
46
  'Progress',
47
+ 'ProgressRing',
47
48
  'Radio',
48
49
  'RadioGroup',
49
50
  'Rating',