@oxyhq/bloom 0.79.0 → 0.80.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 (147) hide show
  1. package/README.md +3 -3
  2. package/lib/commonjs/provider/index.js +11 -7
  3. package/lib/commonjs/provider/index.js.map +1 -1
  4. package/lib/commonjs/scroll/context.js +96 -0
  5. package/lib/commonjs/scroll/context.js.map +1 -0
  6. package/lib/commonjs/scroll/expo-router/index.js +133 -0
  7. package/lib/commonjs/scroll/expo-router/index.js.map +1 -0
  8. package/lib/commonjs/scroll/index.js +85 -21
  9. package/lib/commonjs/scroll/index.js.map +1 -1
  10. package/lib/commonjs/scroll/index.web.js +221 -121
  11. package/lib/commonjs/scroll/index.web.js.map +1 -1
  12. package/lib/commonjs/scroll/scrollable.native.js +58 -0
  13. package/lib/commonjs/scroll/scrollable.native.js.map +1 -0
  14. package/lib/commonjs/scroll/scrollable.web.js +9 -3
  15. package/lib/commonjs/scroll/scrollable.web.js.map +1 -1
  16. package/lib/commonjs/scroll/store.js +47 -25
  17. package/lib/commonjs/scroll/store.js.map +1 -1
  18. package/lib/commonjs/tabs/Tabs.js +263 -63
  19. package/lib/commonjs/tabs/Tabs.js.map +1 -1
  20. package/lib/commonjs/tabs/expo-router/RouterTabs.js +215 -0
  21. package/lib/commonjs/tabs/expo-router/RouterTabs.js.map +1 -0
  22. package/lib/commonjs/tabs/expo-router/index.js +13 -0
  23. package/lib/commonjs/tabs/expo-router/index.js.map +1 -0
  24. package/lib/commonjs/theme/color-policy.js +11 -10
  25. package/lib/commonjs/theme/color-policy.js.map +1 -1
  26. package/lib/module/provider/index.js +10 -6
  27. package/lib/module/provider/index.js.map +1 -1
  28. package/lib/module/scroll/context.js +90 -0
  29. package/lib/module/scroll/context.js.map +1 -0
  30. package/lib/module/scroll/expo-router/index.js +128 -0
  31. package/lib/module/scroll/expo-router/index.js.map +1 -0
  32. package/lib/module/scroll/index.js +80 -21
  33. package/lib/module/scroll/index.js.map +1 -1
  34. package/lib/module/scroll/index.web.js +218 -122
  35. package/lib/module/scroll/index.web.js.map +1 -1
  36. package/lib/module/scroll/scrollable.native.js +54 -0
  37. package/lib/module/scroll/scrollable.native.js.map +1 -0
  38. package/lib/module/scroll/scrollable.web.js +9 -3
  39. package/lib/module/scroll/scrollable.web.js.map +1 -1
  40. package/lib/module/scroll/store.js +47 -25
  41. package/lib/module/scroll/store.js.map +1 -1
  42. package/lib/module/tabs/Tabs.js +271 -65
  43. package/lib/module/tabs/Tabs.js.map +1 -1
  44. package/lib/module/tabs/expo-router/RouterTabs.js +210 -0
  45. package/lib/module/tabs/expo-router/RouterTabs.js.map +1 -0
  46. package/lib/module/tabs/expo-router/index.js +10 -0
  47. package/lib/module/tabs/expo-router/index.js.map +1 -0
  48. package/lib/module/theme/color-policy.js +11 -10
  49. package/lib/module/theme/color-policy.js.map +1 -1
  50. package/lib/typescript/commonjs/provider/index.d.ts +7 -5
  51. package/lib/typescript/commonjs/provider/index.d.ts.map +1 -1
  52. package/lib/typescript/commonjs/scroll/context.d.ts +14 -0
  53. package/lib/typescript/commonjs/scroll/context.d.ts.map +1 -0
  54. package/lib/typescript/commonjs/scroll/expo-router/index.d.ts +7 -0
  55. package/lib/typescript/commonjs/scroll/expo-router/index.d.ts.map +1 -0
  56. package/lib/typescript/commonjs/scroll/index.d.ts +14 -23
  57. package/lib/typescript/commonjs/scroll/index.d.ts.map +1 -1
  58. package/lib/typescript/commonjs/scroll/index.web.d.ts +17 -19
  59. package/lib/typescript/commonjs/scroll/index.web.d.ts.map +1 -1
  60. package/lib/typescript/commonjs/scroll/scrollable.native.d.ts +23 -0
  61. package/lib/typescript/commonjs/scroll/scrollable.native.d.ts.map +1 -0
  62. package/lib/typescript/commonjs/scroll/scrollable.web.d.ts +18 -5
  63. package/lib/typescript/commonjs/scroll/scrollable.web.d.ts.map +1 -1
  64. package/lib/typescript/commonjs/scroll/store.d.ts +41 -22
  65. package/lib/typescript/commonjs/scroll/store.d.ts.map +1 -1
  66. package/lib/typescript/commonjs/scroll/types.d.ts +82 -12
  67. package/lib/typescript/commonjs/scroll/types.d.ts.map +1 -1
  68. package/lib/typescript/commonjs/tabs/Tabs.d.ts +41 -1
  69. package/lib/typescript/commonjs/tabs/Tabs.d.ts.map +1 -1
  70. package/lib/typescript/commonjs/tabs/expo-router/RouterTabs.d.ts +80 -0
  71. package/lib/typescript/commonjs/tabs/expo-router/RouterTabs.d.ts.map +1 -0
  72. package/lib/typescript/commonjs/tabs/expo-router/index.d.ts +9 -0
  73. package/lib/typescript/commonjs/tabs/expo-router/index.d.ts.map +1 -0
  74. package/lib/typescript/commonjs/tabs/types.d.ts +48 -4
  75. package/lib/typescript/commonjs/tabs/types.d.ts.map +1 -1
  76. package/lib/typescript/commonjs/theme/color-policy.d.ts.map +1 -1
  77. package/lib/typescript/module/provider/index.d.ts +7 -5
  78. package/lib/typescript/module/provider/index.d.ts.map +1 -1
  79. package/lib/typescript/module/scroll/context.d.ts +14 -0
  80. package/lib/typescript/module/scroll/context.d.ts.map +1 -0
  81. package/lib/typescript/module/scroll/expo-router/index.d.ts +7 -0
  82. package/lib/typescript/module/scroll/expo-router/index.d.ts.map +1 -0
  83. package/lib/typescript/module/scroll/index.d.ts +14 -23
  84. package/lib/typescript/module/scroll/index.d.ts.map +1 -1
  85. package/lib/typescript/module/scroll/index.web.d.ts +17 -19
  86. package/lib/typescript/module/scroll/index.web.d.ts.map +1 -1
  87. package/lib/typescript/module/scroll/scrollable.native.d.ts +23 -0
  88. package/lib/typescript/module/scroll/scrollable.native.d.ts.map +1 -0
  89. package/lib/typescript/module/scroll/scrollable.web.d.ts +18 -5
  90. package/lib/typescript/module/scroll/scrollable.web.d.ts.map +1 -1
  91. package/lib/typescript/module/scroll/store.d.ts +41 -22
  92. package/lib/typescript/module/scroll/store.d.ts.map +1 -1
  93. package/lib/typescript/module/scroll/types.d.ts +82 -12
  94. package/lib/typescript/module/scroll/types.d.ts.map +1 -1
  95. package/lib/typescript/module/tabs/Tabs.d.ts +41 -1
  96. package/lib/typescript/module/tabs/Tabs.d.ts.map +1 -1
  97. package/lib/typescript/module/tabs/expo-router/RouterTabs.d.ts +80 -0
  98. package/lib/typescript/module/tabs/expo-router/RouterTabs.d.ts.map +1 -0
  99. package/lib/typescript/module/tabs/expo-router/index.d.ts +9 -0
  100. package/lib/typescript/module/tabs/expo-router/index.d.ts.map +1 -0
  101. package/lib/typescript/module/tabs/types.d.ts +48 -4
  102. package/lib/typescript/module/tabs/types.d.ts.map +1 -1
  103. package/lib/typescript/module/theme/color-policy.d.ts.map +1 -1
  104. package/package.json +29 -1
  105. package/src/__tests__/BloomProvider.web.test.tsx +8 -15
  106. package/src/__tests__/Tabs.test.tsx +187 -0
  107. package/src/__tests__/optional-peer-imports.test.ts +7 -2
  108. package/src/__tests__/scroll-expo-router-adapter.test.tsx +164 -0
  109. package/src/__tests__/scroll-native.test.tsx +465 -0
  110. package/src/__tests__/scroll-store.test.ts +41 -17
  111. package/src/__tests__/scroll-web.test.tsx +797 -108
  112. package/src/provider/index.tsx +10 -7
  113. package/src/scroll/context.tsx +107 -0
  114. package/src/scroll/expo-router/index.ts +140 -0
  115. package/src/scroll/index.ts +92 -25
  116. package/src/scroll/index.web.tsx +255 -162
  117. package/src/scroll/scrollable.native.ts +64 -0
  118. package/src/scroll/scrollable.web.ts +30 -8
  119. package/src/scroll/store.ts +47 -25
  120. package/src/scroll/types.ts +82 -12
  121. package/src/tabs/Tabs.tsx +352 -77
  122. package/src/tabs/expo-router/RouterTabs.tsx +268 -0
  123. package/src/tabs/expo-router/index.ts +8 -0
  124. package/src/tabs/types.ts +48 -4
  125. package/src/theme/__tests__/__fixtures__/golden-resolved-tokens.json +5 -5
  126. package/src/theme/__tests__/__snapshots__/visual-gallery.test.tsx.snap +11 -11
  127. package/src/theme/__tests__/policy-legibility.test.ts +10 -7
  128. package/src/theme/color-policy.ts +11 -10
  129. package/lib/commonjs/provider/scroll-provider.js +0 -13
  130. package/lib/commonjs/provider/scroll-provider.js.map +0 -1
  131. package/lib/commonjs/provider/scroll-provider.web.js +0 -13
  132. package/lib/commonjs/provider/scroll-provider.web.js.map +0 -1
  133. package/lib/module/provider/scroll-provider.js +0 -16
  134. package/lib/module/provider/scroll-provider.js.map +0 -1
  135. package/lib/module/provider/scroll-provider.web.js +0 -5
  136. package/lib/module/provider/scroll-provider.web.js.map +0 -1
  137. package/lib/typescript/commonjs/provider/scroll-provider.d.ts +0 -14
  138. package/lib/typescript/commonjs/provider/scroll-provider.d.ts.map +0 -1
  139. package/lib/typescript/commonjs/provider/scroll-provider.web.d.ts +0 -3
  140. package/lib/typescript/commonjs/provider/scroll-provider.web.d.ts.map +0 -1
  141. package/lib/typescript/module/provider/scroll-provider.d.ts +0 -14
  142. package/lib/typescript/module/provider/scroll-provider.d.ts.map +0 -1
  143. package/lib/typescript/module/provider/scroll-provider.web.d.ts +0 -3
  144. package/lib/typescript/module/provider/scroll-provider.web.d.ts.map +0 -1
  145. package/src/__tests__/scroll-native.test.ts +0 -25
  146. package/src/provider/scroll-provider.ts +0 -13
  147. package/src/provider/scroll-provider.web.ts +0 -2
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * The write half of a scrollable, on native. There is no read half: native
5
+ * offers no way to sample a list's offset from outside it, so offsets arrive
6
+ * through the `onScroll` binding the hook returns instead.
7
+ */
8
+
9
+ function hasScrollToOffset(value) {
10
+ return typeof value === 'object' && value !== null && typeof value.scrollToOffset === 'function';
11
+ }
12
+ function hasScrollTo(value) {
13
+ return typeof value === 'object' && value !== null && typeof value.scrollTo === 'function';
14
+ }
15
+
16
+ /**
17
+ * Build a {@link NativeScroller} for a target.
18
+ *
19
+ * `scrollToOffset` (`FlatList`, `FlashList`) is preferred over `scrollTo`
20
+ * (`ScrollView`) because a list exposes both shapes on some versions and only
21
+ * the former accounts for the list's own header. The `'window'` sentinel has no
22
+ * native meaning — there is no document scroller — so it resolves to a no-op
23
+ * rather than an error: a call site shared with web legitimately passes it.
24
+ *
25
+ * The handle is re-resolved on every write; it is never cached, because a ref
26
+ * can be swapped or detached between the schedule and the write.
27
+ */
28
+ export function createScroller(target) {
29
+ if (target === 'window') {
30
+ return {
31
+ setOffset: () => undefined
32
+ };
33
+ }
34
+ return {
35
+ setOffset: offset => {
36
+ const current = target.current;
37
+ if (current == null) return;
38
+ if (hasScrollToOffset(current)) {
39
+ current.scrollToOffset({
40
+ offset,
41
+ animated: false
42
+ });
43
+ return;
44
+ }
45
+ if (hasScrollTo(current)) {
46
+ current.scrollTo({
47
+ y: offset,
48
+ animated: false
49
+ });
50
+ }
51
+ }
52
+ };
53
+ }
54
+ //# sourceMappingURL=scrollable.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["hasScrollToOffset","value","scrollToOffset","hasScrollTo","scrollTo","createScroller","target","setOffset","undefined","offset","current","animated","y"],"sourceRoot":"../../../src","sources":["scroll/scrollable.native.ts"],"mappings":";;AAEA;AACA;AACA;AACA;AACA;;AAKA,SAASA,iBAAiBA,CACxBC,KAAc,EAC+C;EAC7D,OACE,OAAOA,KAAK,KAAK,QAAQ,IACzBA,KAAK,KAAK,IAAI,IACd,OAAQA,KAAK,CAAsBC,cAAc,KAAK,UAAU;AAEpE;AAEA,SAASC,WAAWA,CAClBF,KAAc,EACyC;EACvD,OACE,OAAOA,KAAK,KAAK,QAAQ,IACzBA,KAAK,KAAK,IAAI,IACd,OAAQA,KAAK,CAAsBG,QAAQ,KAAK,UAAU;AAE9D;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,cAAcA,CAC5BC,MAA+B,EACf;EAChB,IAAIA,MAAM,KAAK,QAAQ,EAAE;IACvB,OAAO;MAAEC,SAAS,EAAEA,CAAA,KAAMC;IAAU,CAAC;EACvC;EAEA,OAAO;IACLD,SAAS,EAAGE,MAAM,IAAK;MACrB,MAAMC,OAAO,GAAGJ,MAAM,CAACI,OAAO;MAC9B,IAAIA,OAAO,IAAI,IAAI,EAAE;MACrB,IAAIV,iBAAiB,CAACU,OAAO,CAAC,EAAE;QAC9BA,OAAO,CAACR,cAAc,CAAC;UAAEO,MAAM;UAAEE,QAAQ,EAAE;QAAM,CAAC,CAAC;QACnD;MACF;MACA,IAAIR,WAAW,CAACO,OAAO,CAAC,EAAE;QACxBA,OAAO,CAACN,QAAQ,CAAC;UAAEQ,CAAC,EAAEH,MAAM;UAAEE,QAAQ,EAAE;QAAM,CAAC,CAAC;MAClD;IACF;EACF,CAAC;AACH","ignoreList":[]}
@@ -44,7 +44,12 @@ export function createScroller(target) {
44
44
  setOffset: offset => {
45
45
  if (typeof window !== 'undefined') window.scrollTo(0, offset);
46
46
  },
47
- canScroll: () => true
47
+ getMaxOffset: () => {
48
+ if (typeof window === 'undefined' || typeof document === 'undefined') {
49
+ return 0;
50
+ }
51
+ return Math.max(0, document.documentElement.scrollHeight - window.innerHeight);
52
+ }
48
53
  };
49
54
  }
50
55
  return {
@@ -56,9 +61,10 @@ export function createScroller(target) {
56
61
  const element = resolveElement(target);
57
62
  if (element) element.scrollTop = offset;
58
63
  },
59
- canScroll: () => {
64
+ getMaxOffset: () => {
60
65
  const element = resolveElement(target);
61
- return element ? element.scrollHeight > element.clientHeight : false;
66
+ if (!element) return 0;
67
+ return Math.max(0, element.scrollHeight - element.clientHeight);
62
68
  }
63
69
  };
64
70
  }
@@ -1 +1 @@
1
- {"version":3,"names":["isElement","value","HTMLElement","hasGetScrollableNode","getScrollableNode","resolveElement","target","current","node","createScroller","getOffset","window","scrollY","setOffset","offset","scrollTo","canScroll","element","scrollTop","scrollHeight","clientHeight"],"sourceRoot":"../../../src","sources":["scroll/scrollable.web.ts"],"mappings":";;AAEA;AACA;AACA;AACA;AACA;;AAkBA,SAASA,SAASA,CAACC,KAAc,EAAwB;EACvD,OAAO,OAAOC,WAAW,KAAK,WAAW,IAAID,KAAK,YAAYC,WAAW;AAC3E;AAEA,SAASC,oBAAoBA,CAC3BF,KAAc,EACkD;EAChE,OACE,OAAOA,KAAK,KAAK,QAAQ,IACzBA,KAAK,KAAK,IAAI,IACd,OAAQA,KAAK,CAAsBG,iBAAiB,KAAK,UAAU;AAEvE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASC,cAAcA,CAACC,MAA+B,EAAsB;EAC3E,IAAIA,MAAM,KAAK,QAAQ,EAAE,OAAO,IAAI;EAEpC,MAAMC,OAAO,GAAID,MAAM,CAA0BC,OAAO;EACxD,IAAIA,OAAO,IAAI,IAAI,EAAE,OAAO,IAAI;EAEhC,IAAIP,SAAS,CAACO,OAAO,CAAC,EAAE,OAAOA,OAAO;EAEtC,IAAIJ,oBAAoB,CAACI,OAAO,CAAC,EAAE;IACjC,MAAMC,IAAI,GAAGD,OAAO,CAACH,iBAAiB,CAAC,CAAC;IACxC,IAAIJ,SAAS,CAACQ,IAAI,CAAC,EAAE,OAAOA,IAAI;EAClC;EAEA,OAAO,IAAI;AACb;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,cAAcA,CAACH,MAA+B,EAAoB;EAChF,IAAIA,MAAM,KAAK,QAAQ,EAAE;IACvB,OAAO;MACLI,SAAS,EAAEA,CAAA,KAAO,OAAOC,MAAM,KAAK,WAAW,GAAG,CAAC,GAAGA,MAAM,CAACC,OAAQ;MACrEC,SAAS,EAAGC,MAAM,IAAK;QACrB,IAAI,OAAOH,MAAM,KAAK,WAAW,EAAEA,MAAM,CAACI,QAAQ,CAAC,CAAC,EAAED,MAAM,CAAC;MAC/D,CAAC;MACDE,SAAS,EAAEA,CAAA,KAAM;IACnB,CAAC;EACH;EAEA,OAAO;IACLN,SAAS,EAAEA,CAAA,KAAM;MACf,MAAMO,OAAO,GAAGZ,cAAc,CAACC,MAAM,CAAC;MACtC,OAAOW,OAAO,GAAGA,OAAO,CAACC,SAAS,GAAG,CAAC;IACxC,CAAC;IACDL,SAAS,EAAGC,MAAM,IAAK;MACrB,MAAMG,OAAO,GAAGZ,cAAc,CAACC,MAAM,CAAC;MACtC,IAAIW,OAAO,EAAEA,OAAO,CAACC,SAAS,GAAGJ,MAAM;IACzC,CAAC;IACDE,SAAS,EAAEA,CAAA,KAAM;MACf,MAAMC,OAAO,GAAGZ,cAAc,CAACC,MAAM,CAAC;MACtC,OAAOW,OAAO,GAAGA,OAAO,CAACE,YAAY,GAAGF,OAAO,CAACG,YAAY,GAAG,KAAK;IACtE;EACF,CAAC;AACH","ignoreList":[]}
1
+ {"version":3,"names":["isElement","value","HTMLElement","hasGetScrollableNode","getScrollableNode","resolveElement","target","current","node","createScroller","getOffset","window","scrollY","setOffset","offset","scrollTo","getMaxOffset","document","Math","max","documentElement","scrollHeight","innerHeight","element","scrollTop","clientHeight"],"sourceRoot":"../../../src","sources":["scroll/scrollable.web.ts"],"mappings":";;AAEA;AACA;AACA;AACA;AACA;;AA+BA,SAASA,SAASA,CAACC,KAAc,EAAwB;EACvD,OAAO,OAAOC,WAAW,KAAK,WAAW,IAAID,KAAK,YAAYC,WAAW;AAC3E;AAEA,SAASC,oBAAoBA,CAC3BF,KAAc,EACkD;EAChE,OACE,OAAOA,KAAK,KAAK,QAAQ,IACzBA,KAAK,KAAK,IAAI,IACd,OAAQA,KAAK,CAAsBG,iBAAiB,KAAK,UAAU;AAEvE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASC,cAAcA,CAACC,MAA+B,EAAsB;EAC3E,IAAIA,MAAM,KAAK,QAAQ,EAAE,OAAO,IAAI;EAEpC,MAAMC,OAAO,GAAID,MAAM,CAA0BC,OAAO;EACxD,IAAIA,OAAO,IAAI,IAAI,EAAE,OAAO,IAAI;EAEhC,IAAIP,SAAS,CAACO,OAAO,CAAC,EAAE,OAAOA,OAAO;EAEtC,IAAIJ,oBAAoB,CAACI,OAAO,CAAC,EAAE;IACjC,MAAMC,IAAI,GAAGD,OAAO,CAACH,iBAAiB,CAAC,CAAC;IACxC,IAAIJ,SAAS,CAACQ,IAAI,CAAC,EAAE,OAAOA,IAAI;EAClC;EAEA,OAAO,IAAI;AACb;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,cAAcA,CAACH,MAA+B,EAAoB;EAChF,IAAIA,MAAM,KAAK,QAAQ,EAAE;IACvB,OAAO;MACLI,SAAS,EAAEA,CAAA,KAAO,OAAOC,MAAM,KAAK,WAAW,GAAG,CAAC,GAAGA,MAAM,CAACC,OAAQ;MACrEC,SAAS,EAAGC,MAAM,IAAK;QACrB,IAAI,OAAOH,MAAM,KAAK,WAAW,EAAEA,MAAM,CAACI,QAAQ,CAAC,CAAC,EAAED,MAAM,CAAC;MAC/D,CAAC;MACDE,YAAY,EAAEA,CAAA,KAAM;QAClB,IAAI,OAAOL,MAAM,KAAK,WAAW,IAAI,OAAOM,QAAQ,KAAK,WAAW,EAAE;UACpE,OAAO,CAAC;QACV;QACA,OAAOC,IAAI,CAACC,GAAG,CACb,CAAC,EACDF,QAAQ,CAACG,eAAe,CAACC,YAAY,GAAGV,MAAM,CAACW,WACjD,CAAC;MACH;IACF,CAAC;EACH;EAEA,OAAO;IACLZ,SAAS,EAAEA,CAAA,KAAM;MACf,MAAMa,OAAO,GAAGlB,cAAc,CAACC,MAAM,CAAC;MACtC,OAAOiB,OAAO,GAAGA,OAAO,CAACC,SAAS,GAAG,CAAC;IACxC,CAAC;IACDX,SAAS,EAAGC,MAAM,IAAK;MACrB,MAAMS,OAAO,GAAGlB,cAAc,CAACC,MAAM,CAAC;MACtC,IAAIiB,OAAO,EAAEA,OAAO,CAACC,SAAS,GAAGV,MAAM;IACzC,CAAC;IACDE,YAAY,EAAEA,CAAA,KAAM;MAClB,MAAMO,OAAO,GAAGlB,cAAc,CAACC,MAAM,CAAC;MACtC,IAAI,CAACiB,OAAO,EAAE,OAAO,CAAC;MACtB,OAAOL,IAAI,CAACC,GAAG,CAAC,CAAC,EAAEI,OAAO,CAACF,YAAY,GAAGE,OAAO,CAACE,YAAY,CAAC;IACjE;EACF,CAAC;AACH","ignoreList":[]}
@@ -5,16 +5,12 @@
5
5
  *
6
6
  * This file deliberately contains NO React and NO DOM/native imports so the
7
7
  * logic can be unit-tested in isolation and shared verbatim by the web and
8
- * native barrels. The web barrel drives it with real scroll offsets; the
9
- * native barrel never instantiates it (native-stack already restores scroll).
8
+ * native barrels.
10
9
  */
11
-
12
10
  /**
13
- * Separator between the navigation route key and an optional caller-supplied
14
- * sub-key. A route may host more than one independently-scrolling list (e.g.
15
- * a tabbed profile screen), so each list contributes its own sub-key.
11
+ * Separator between the two components of a storage key.
16
12
  *
17
- * `\0` (NUL) can never appear in a React Navigation route key or in a
13
+ * `\0` (NUL) can never appear in a router-derived content id or in a
18
14
  * developer-authored sub-key, so it is collision-free as a delimiter. It is
19
15
  * written as an escape sequence (not a literal byte) so the source stays
20
16
  * text-diffable.
@@ -22,28 +18,48 @@
22
18
  const COMPOSITE_KEY_SEPARATOR = '\0';
23
19
 
24
20
  /**
25
- * Derive the storage key for a scrollable from its owning route key and an
26
- * optional caller sub-key.
21
+ * Derive the storage key for a scrollable from WHAT its screen is showing plus
22
+ * an optional caller sub-key.
23
+ *
24
+ * The key is CONTENT identity, deliberately not the navigation entry. An offset
25
+ * belongs to what the user was looking at, so returning to it restores however
26
+ * they got there — browser Back or Forward, a tab press, an in-app link — and
27
+ * only content never seen this session opens at the top. Keying on the entry
28
+ * would defeat that: a tab press and `router.replace` both mint a fresh entry,
29
+ * so both would open at the top even though the user has been there.
30
+ *
31
+ * The trade, chosen rather than overlooked: the same content occupying two LIVE
32
+ * entries now shares one offset. Pushing `/@alice` on top of `/@alice` in a
33
+ * native stack restores the first one's position instead of opening at the top,
34
+ * and while both are mounted each writes to the same key. That is the price of
35
+ * a tab press restoring, which is the behaviour that was asked for.
27
36
  *
28
- * - `routeKey` is React Navigation's stable per-route `route.key`.
29
- * - `subKey` distinguishes multiple scrollables that share a single route.
37
+ * The key is always the same two-field composite, with an absent sub-key
38
+ * written as empty, so two different identities can never collapse onto one key
39
+ * by omission.
30
40
  *
31
- * Returns `null` when there is no route key to anchor against (the scrollable
32
- * is not inside a navigator), which the caller treats as "do not persist".
41
+ * Returns `null` when there is no content id to anchor against (the scrollable
42
+ * is not inside a navigator, or the adapter cannot answer), which every caller
43
+ * treats as "do not persist and do not restore".
33
44
  */
34
- export function deriveScrollKey(routeKey, subKey) {
35
- if (!routeKey) return null;
36
- if (subKey === undefined || subKey === '') return routeKey;
37
- return `${routeKey}${COMPOSITE_KEY_SEPARATOR}${subKey}`;
45
+ export function deriveScrollKey(contentId, subKey) {
46
+ if (!contentId) return null;
47
+ return [contentId, subKey ?? ''].join(COMPOSITE_KEY_SEPARATOR);
38
48
  }
39
49
 
40
50
  /**
41
51
  * In-memory map of `scrollKey -> last-known scroll offset`.
42
52
  *
43
- * Mirrors the semantics of Bluesky's `Map<screenKey, scrollY>`: offsets live
44
- * only for the lifetime of the document/session. We never persist them — a
45
- * full reload should start at the top and we never auto-evict, because a
46
- * route can be revisited via browser Forward/Back long after it blurred.
53
+ * Offsets live only for the lifetime of the document/session. We never persist
54
+ * them a full reload should start at the top and we never auto-evict,
55
+ * because an entry can be revisited via browser Forward/Back long after it
56
+ * blurred.
57
+ *
58
+ * Deliberately an instance held in React context rather than a module-level
59
+ * singleton: a dependency tree can legitimately contain two copies of Bloom
60
+ * (a hoisted one plus a nested one under another Oxy package), and a
61
+ * module-global would then exist twice with no way for either half to see the
62
+ * other's offsets.
47
63
  */
48
64
  export class ScrollOffsetStore {
49
65
  offsets = new Map();
@@ -54,19 +70,25 @@ export class ScrollOffsetStore {
54
70
  }
55
71
 
56
72
  /**
57
- * Read the saved offset for a key. Returns `0` when nothing was saved, so
58
- * callers can restore unconditionally (an unseen list restores to the top).
73
+ * Read the saved offset for a key. Returns `0` when nothing was saved, which
74
+ * is the same value a caller writes when {@link has} is false — an unseen
75
+ * list restores to the top.
59
76
  */
60
77
  read(key) {
61
78
  return this.offsets.get(key) ?? 0;
62
79
  }
63
80
 
64
- /** Whether an offset was ever saved for this key. */
81
+ /**
82
+ * Whether an offset was ever saved for this key. This — not `read() > 0` —
83
+ * is what separates "restore" from "reset": a key that was never seen and a
84
+ * key deliberately saved at the top both read 0, and only the store knows
85
+ * which is which.
86
+ */
65
87
  has(key) {
66
88
  return this.offsets.has(key);
67
89
  }
68
90
 
69
- /** Drop a saved offset (e.g. when a route is permanently removed). */
91
+ /** Drop a saved offset (e.g. when an entry is permanently removed). */
70
92
  forget(key) {
71
93
  this.offsets.delete(key);
72
94
  }
@@ -1 +1 @@
1
- {"version":3,"names":["COMPOSITE_KEY_SEPARATOR","deriveScrollKey","routeKey","subKey","undefined","ScrollOffsetStore","offsets","Map","save","key","offset","set","read","get","has","forget","delete","clear","size"],"sourceRoot":"../../../src","sources":["scroll/store.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMA,uBAAuB,GAAG,IAAI;;AAEpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAC7BC,QAA4B,EAC5BC,MAAe,EACA;EACf,IAAI,CAACD,QAAQ,EAAE,OAAO,IAAI;EAC1B,IAAIC,MAAM,KAAKC,SAAS,IAAID,MAAM,KAAK,EAAE,EAAE,OAAOD,QAAQ;EAC1D,OAAO,GAAGA,QAAQ,GAAGF,uBAAuB,GAAGG,MAAM,EAAE;AACzD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAME,iBAAiB,CAAC;EACZC,OAAO,GAAG,IAAIC,GAAG,CAAiB,CAAC;;EAEpD;EACAC,IAAIA,CAACC,GAAW,EAAEC,MAAc,EAAQ;IACtC,IAAI,CAACJ,OAAO,CAACK,GAAG,CAACF,GAAG,EAAEC,MAAM,GAAG,CAAC,GAAGA,MAAM,GAAG,CAAC,CAAC;EAChD;;EAEA;AACF;AACA;AACA;EACEE,IAAIA,CAACH,GAAW,EAAU;IACxB,OAAO,IAAI,CAACH,OAAO,CAACO,GAAG,CAACJ,GAAG,CAAC,IAAI,CAAC;EACnC;;EAEA;EACAK,GAAGA,CAACL,GAAW,EAAW;IACxB,OAAO,IAAI,CAACH,OAAO,CAACQ,GAAG,CAACL,GAAG,CAAC;EAC9B;;EAEA;EACAM,MAAMA,CAACN,GAAW,EAAQ;IACxB,IAAI,CAACH,OAAO,CAACU,MAAM,CAACP,GAAG,CAAC;EAC1B;;EAEA;EACAQ,KAAKA,CAAA,EAAS;IACZ,IAAI,CAACX,OAAO,CAACW,KAAK,CAAC,CAAC;EACtB;;EAEA;EACA,IAAIC,IAAIA,CAAA,EAAW;IACjB,OAAO,IAAI,CAACZ,OAAO,CAACY,IAAI;EAC1B;AACF","ignoreList":[]}
1
+ {"version":3,"names":["COMPOSITE_KEY_SEPARATOR","deriveScrollKey","contentId","subKey","join","ScrollOffsetStore","offsets","Map","save","key","offset","set","read","get","has","forget","delete","clear","size"],"sourceRoot":"../../../src","sources":["scroll/store.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMA,uBAAuB,GAAG,IAAI;;AAEpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAC7BC,SAAwB,EACxBC,MAAe,EACA;EACf,IAAI,CAACD,SAAS,EAAE,OAAO,IAAI;EAC3B,OAAO,CAACA,SAAS,EAAEC,MAAM,IAAI,EAAE,CAAC,CAACC,IAAI,CAACJ,uBAAuB,CAAC;AAChE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMK,iBAAiB,CAAC;EACZC,OAAO,GAAG,IAAIC,GAAG,CAAiB,CAAC;;EAEpD;EACAC,IAAIA,CAACC,GAAW,EAAEC,MAAc,EAAQ;IACtC,IAAI,CAACJ,OAAO,CAACK,GAAG,CAACF,GAAG,EAAEC,MAAM,GAAG,CAAC,GAAGA,MAAM,GAAG,CAAC,CAAC;EAChD;;EAEA;AACF;AACA;AACA;AACA;EACEE,IAAIA,CAACH,GAAW,EAAU;IACxB,OAAO,IAAI,CAACH,OAAO,CAACO,GAAG,CAACJ,GAAG,CAAC,IAAI,CAAC;EACnC;;EAEA;AACF;AACA;AACA;AACA;AACA;EACEK,GAAGA,CAACL,GAAW,EAAW;IACxB,OAAO,IAAI,CAACH,OAAO,CAACQ,GAAG,CAACL,GAAG,CAAC;EAC9B;;EAEA;EACAM,MAAMA,CAACN,GAAW,EAAQ;IACxB,IAAI,CAACH,OAAO,CAACU,MAAM,CAACP,GAAG,CAAC;EAC1B;;EAEA;EACAQ,KAAKA,CAAA,EAAS;IACZ,IAAI,CAACX,OAAO,CAACW,KAAK,CAAC,CAAC;EACtB;;EAEA;EACA,IAAIC,IAAIA,CAAA,EAAW;IACjB,OAAO,IAAI,CAACZ,OAAO,CAACY,IAAI;EAC1B;AACF","ignoreList":[]}