@chenzy-design/core 0.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 (310) hide show
  1. package/LICENSE +21 -0
  2. package/dist/back-top.d.ts +16 -0
  3. package/dist/back-top.d.ts.map +1 -0
  4. package/dist/back-top.js +29 -0
  5. package/dist/back-top.js.map +1 -0
  6. package/dist/back-top.test.d.ts +2 -0
  7. package/dist/back-top.test.d.ts.map +1 -0
  8. package/dist/back-top.test.js +44 -0
  9. package/dist/back-top.test.js.map +1 -0
  10. package/dist/banner.d.ts +19 -0
  11. package/dist/banner.d.ts.map +1 -0
  12. package/dist/banner.js +20 -0
  13. package/dist/banner.js.map +1 -0
  14. package/dist/banner.test.d.ts +2 -0
  15. package/dist/banner.test.d.ts.map +1 -0
  16. package/dist/banner.test.js +29 -0
  17. package/dist/banner.test.js.map +1 -0
  18. package/dist/breakpoints.d.ts +30 -0
  19. package/dist/breakpoints.d.ts.map +1 -0
  20. package/dist/breakpoints.js +45 -0
  21. package/dist/breakpoints.js.map +1 -0
  22. package/dist/breakpoints.test.d.ts +2 -0
  23. package/dist/breakpoints.test.d.ts.map +1 -0
  24. package/dist/breakpoints.test.js +46 -0
  25. package/dist/breakpoints.test.js.map +1 -0
  26. package/dist/calendar.d.ts +63 -0
  27. package/dist/calendar.d.ts.map +1 -0
  28. package/dist/calendar.js +94 -0
  29. package/dist/calendar.js.map +1 -0
  30. package/dist/calendar.test.d.ts +2 -0
  31. package/dist/calendar.test.d.ts.map +1 -0
  32. package/dist/calendar.test.js +88 -0
  33. package/dist/calendar.test.js.map +1 -0
  34. package/dist/cascader.d.ts +64 -0
  35. package/dist/cascader.d.ts.map +1 -0
  36. package/dist/cascader.js +79 -0
  37. package/dist/cascader.js.map +1 -0
  38. package/dist/cascader.test.d.ts +2 -0
  39. package/dist/cascader.test.d.ts.map +1 -0
  40. package/dist/cascader.test.js +107 -0
  41. package/dist/cascader.test.js.map +1 -0
  42. package/dist/color.d.ts +70 -0
  43. package/dist/color.d.ts.map +1 -0
  44. package/dist/color.js +217 -0
  45. package/dist/color.js.map +1 -0
  46. package/dist/color.test.d.ts +2 -0
  47. package/dist/color.test.d.ts.map +1 -0
  48. package/dist/color.test.js +161 -0
  49. package/dist/color.test.js.map +1 -0
  50. package/dist/config-provider.d.ts +57 -0
  51. package/dist/config-provider.d.ts.map +1 -0
  52. package/dist/config-provider.js +49 -0
  53. package/dist/config-provider.js.map +1 -0
  54. package/dist/config-provider.test.d.ts +2 -0
  55. package/dist/config-provider.test.d.ts.map +1 -0
  56. package/dist/config-provider.test.js +76 -0
  57. package/dist/config-provider.test.js.map +1 -0
  58. package/dist/copyable.d.ts +43 -0
  59. package/dist/copyable.d.ts.map +1 -0
  60. package/dist/copyable.js +102 -0
  61. package/dist/copyable.js.map +1 -0
  62. package/dist/copyable.test.d.ts +2 -0
  63. package/dist/copyable.test.d.ts.map +1 -0
  64. package/dist/copyable.test.js +97 -0
  65. package/dist/copyable.test.js.map +1 -0
  66. package/dist/date.d.ts +86 -0
  67. package/dist/date.d.ts.map +1 -0
  68. package/dist/date.js +226 -0
  69. package/dist/date.js.map +1 -0
  70. package/dist/date.test.d.ts +2 -0
  71. package/dist/date.test.d.ts.map +1 -0
  72. package/dist/date.test.js +171 -0
  73. package/dist/date.test.js.map +1 -0
  74. package/dist/dismiss.d.ts +28 -0
  75. package/dist/dismiss.d.ts.map +1 -0
  76. package/dist/dismiss.js +42 -0
  77. package/dist/dismiss.js.map +1 -0
  78. package/dist/editable.d.ts +59 -0
  79. package/dist/editable.d.ts.map +1 -0
  80. package/dist/editable.js +85 -0
  81. package/dist/editable.js.map +1 -0
  82. package/dist/editable.test.d.ts +2 -0
  83. package/dist/editable.test.d.ts.map +1 -0
  84. package/dist/editable.test.js +111 -0
  85. package/dist/editable.test.js.map +1 -0
  86. package/dist/ellipsis.d.ts +76 -0
  87. package/dist/ellipsis.d.ts.map +1 -0
  88. package/dist/ellipsis.js +99 -0
  89. package/dist/ellipsis.js.map +1 -0
  90. package/dist/ellipsis.test.d.ts +2 -0
  91. package/dist/ellipsis.test.d.ts.map +1 -0
  92. package/dist/ellipsis.test.js +94 -0
  93. package/dist/ellipsis.test.js.map +1 -0
  94. package/dist/floating.d.ts +78 -0
  95. package/dist/floating.d.ts.map +1 -0
  96. package/dist/floating.js +169 -0
  97. package/dist/floating.js.map +1 -0
  98. package/dist/floating.test.d.ts +2 -0
  99. package/dist/floating.test.d.ts.map +1 -0
  100. package/dist/floating.test.js +169 -0
  101. package/dist/floating.test.js.map +1 -0
  102. package/dist/focus-trap.d.ts +24 -0
  103. package/dist/focus-trap.d.ts.map +1 -0
  104. package/dist/focus-trap.js +64 -0
  105. package/dist/focus-trap.js.map +1 -0
  106. package/dist/form.d.ts +131 -0
  107. package/dist/form.d.ts.map +1 -0
  108. package/dist/form.js +257 -0
  109. package/dist/form.js.map +1 -0
  110. package/dist/form.test.d.ts +2 -0
  111. package/dist/form.test.d.ts.map +1 -0
  112. package/dist/form.test.js +323 -0
  113. package/dist/form.test.js.map +1 -0
  114. package/dist/highlight.d.ts +57 -0
  115. package/dist/highlight.d.ts.map +1 -0
  116. package/dist/highlight.js +124 -0
  117. package/dist/highlight.js.map +1 -0
  118. package/dist/highlight.test.d.ts +2 -0
  119. package/dist/highlight.test.d.ts.map +1 -0
  120. package/dist/highlight.test.js +155 -0
  121. package/dist/highlight.test.js.map +1 -0
  122. package/dist/id.d.ts +4 -0
  123. package/dist/id.d.ts.map +1 -0
  124. package/dist/id.js +14 -0
  125. package/dist/id.js.map +1 -0
  126. package/dist/id.test.d.ts +2 -0
  127. package/dist/id.test.d.ts.map +1 -0
  128. package/dist/id.test.js +13 -0
  129. package/dist/id.test.js.map +1 -0
  130. package/dist/index.d.ts +46 -0
  131. package/dist/index.d.ts.map +1 -0
  132. package/dist/index.js +45 -0
  133. package/dist/index.js.map +1 -0
  134. package/dist/inert-background.d.ts +27 -0
  135. package/dist/inert-background.d.ts.map +1 -0
  136. package/dist/inert-background.js +92 -0
  137. package/dist/inert-background.js.map +1 -0
  138. package/dist/inert-background.test.d.ts +2 -0
  139. package/dist/inert-background.test.d.ts.map +1 -0
  140. package/dist/inert-background.test.js +62 -0
  141. package/dist/inert-background.test.js.map +1 -0
  142. package/dist/input-number.d.ts +34 -0
  143. package/dist/input-number.d.ts.map +1 -0
  144. package/dist/input-number.js +69 -0
  145. package/dist/input-number.js.map +1 -0
  146. package/dist/input-number.test.d.ts +2 -0
  147. package/dist/input-number.test.d.ts.map +1 -0
  148. package/dist/input-number.test.js +74 -0
  149. package/dist/input-number.test.js.map +1 -0
  150. package/dist/list-selection.d.ts +38 -0
  151. package/dist/list-selection.d.ts.map +1 -0
  152. package/dist/list-selection.js +61 -0
  153. package/dist/list-selection.js.map +1 -0
  154. package/dist/list-selection.test.d.ts +2 -0
  155. package/dist/list-selection.test.d.ts.map +1 -0
  156. package/dist/list-selection.test.js +61 -0
  157. package/dist/list-selection.test.js.map +1 -0
  158. package/dist/live-announcer.d.ts +38 -0
  159. package/dist/live-announcer.d.ts.map +1 -0
  160. package/dist/live-announcer.js +89 -0
  161. package/dist/live-announcer.js.map +1 -0
  162. package/dist/live-announcer.test.d.ts +2 -0
  163. package/dist/live-announcer.test.d.ts.map +1 -0
  164. package/dist/live-announcer.test.js +70 -0
  165. package/dist/live-announcer.test.js.map +1 -0
  166. package/dist/lottie-icon.d.ts +88 -0
  167. package/dist/lottie-icon.d.ts.map +1 -0
  168. package/dist/lottie-icon.js +84 -0
  169. package/dist/lottie-icon.js.map +1 -0
  170. package/dist/lottie-icon.test.d.ts +2 -0
  171. package/dist/lottie-icon.test.d.ts.map +1 -0
  172. package/dist/lottie-icon.test.js +88 -0
  173. package/dist/lottie-icon.test.js.map +1 -0
  174. package/dist/notification.d.ts +61 -0
  175. package/dist/notification.d.ts.map +1 -0
  176. package/dist/notification.js +133 -0
  177. package/dist/notification.js.map +1 -0
  178. package/dist/notification.test.d.ts +2 -0
  179. package/dist/notification.test.d.ts.map +1 -0
  180. package/dist/notification.test.js +103 -0
  181. package/dist/notification.test.js.map +1 -0
  182. package/dist/overflow-list.d.ts +102 -0
  183. package/dist/overflow-list.d.ts.map +1 -0
  184. package/dist/overflow-list.js +159 -0
  185. package/dist/overflow-list.js.map +1 -0
  186. package/dist/overflow-list.test.d.ts +2 -0
  187. package/dist/overflow-list.test.d.ts.map +1 -0
  188. package/dist/overflow-list.test.js +223 -0
  189. package/dist/overflow-list.test.js.map +1 -0
  190. package/dist/pagination.d.ts +51 -0
  191. package/dist/pagination.d.ts.map +1 -0
  192. package/dist/pagination.js +127 -0
  193. package/dist/pagination.js.map +1 -0
  194. package/dist/pagination.test.d.ts +2 -0
  195. package/dist/pagination.test.d.ts.map +1 -0
  196. package/dist/pagination.test.js +147 -0
  197. package/dist/pagination.test.js.map +1 -0
  198. package/dist/progress.d.ts +64 -0
  199. package/dist/progress.d.ts.map +1 -0
  200. package/dist/progress.js +92 -0
  201. package/dist/progress.js.map +1 -0
  202. package/dist/progress.test.d.ts +2 -0
  203. package/dist/progress.test.d.ts.map +1 -0
  204. package/dist/progress.test.js +79 -0
  205. package/dist/progress.test.js.map +1 -0
  206. package/dist/resize-observer.d.ts +133 -0
  207. package/dist/resize-observer.d.ts.map +1 -0
  208. package/dist/resize-observer.js +358 -0
  209. package/dist/resize-observer.js.map +1 -0
  210. package/dist/resize-observer.test.d.ts +2 -0
  211. package/dist/resize-observer.test.d.ts.map +1 -0
  212. package/dist/resize-observer.test.js +377 -0
  213. package/dist/resize-observer.test.js.map +1 -0
  214. package/dist/roving.d.ts +26 -0
  215. package/dist/roving.d.ts.map +1 -0
  216. package/dist/roving.js +61 -0
  217. package/dist/roving.js.map +1 -0
  218. package/dist/roving.test.d.ts +2 -0
  219. package/dist/roving.test.d.ts.map +1 -0
  220. package/dist/roving.test.js +48 -0
  221. package/dist/roving.test.js.map +1 -0
  222. package/dist/scroll-list.d.ts +81 -0
  223. package/dist/scroll-list.d.ts.map +1 -0
  224. package/dist/scroll-list.js +175 -0
  225. package/dist/scroll-list.js.map +1 -0
  226. package/dist/scroll-list.test.d.ts +2 -0
  227. package/dist/scroll-list.test.d.ts.map +1 -0
  228. package/dist/scroll-list.test.js +135 -0
  229. package/dist/scroll-list.test.js.map +1 -0
  230. package/dist/scroll-lock.d.ts +11 -0
  231. package/dist/scroll-lock.d.ts.map +1 -0
  232. package/dist/scroll-lock.js +45 -0
  233. package/dist/scroll-lock.js.map +1 -0
  234. package/dist/scroll-lock.test.d.ts +2 -0
  235. package/dist/scroll-lock.test.d.ts.map +1 -0
  236. package/dist/scroll-lock.test.js +55 -0
  237. package/dist/scroll-lock.test.js.map +1 -0
  238. package/dist/sider.d.ts +26 -0
  239. package/dist/sider.d.ts.map +1 -0
  240. package/dist/sider.js +55 -0
  241. package/dist/sider.js.map +1 -0
  242. package/dist/sider.test.d.ts +2 -0
  243. package/dist/sider.test.d.ts.map +1 -0
  244. package/dist/sider.test.js +29 -0
  245. package/dist/sider.test.js.map +1 -0
  246. package/dist/spin.d.ts +25 -0
  247. package/dist/spin.d.ts.map +1 -0
  248. package/dist/spin.js +96 -0
  249. package/dist/spin.js.map +1 -0
  250. package/dist/spin.test.d.ts +2 -0
  251. package/dist/spin.test.d.ts.map +1 -0
  252. package/dist/spin.test.js +80 -0
  253. package/dist/spin.test.js.map +1 -0
  254. package/dist/table.d.ts +101 -0
  255. package/dist/table.d.ts.map +1 -0
  256. package/dist/table.js +244 -0
  257. package/dist/table.js.map +1 -0
  258. package/dist/table.test.d.ts +2 -0
  259. package/dist/table.test.d.ts.map +1 -0
  260. package/dist/table.test.js +184 -0
  261. package/dist/table.test.js.map +1 -0
  262. package/dist/textarea.d.ts +48 -0
  263. package/dist/textarea.d.ts.map +1 -0
  264. package/dist/textarea.js +76 -0
  265. package/dist/textarea.js.map +1 -0
  266. package/dist/textarea.test.d.ts +2 -0
  267. package/dist/textarea.test.d.ts.map +1 -0
  268. package/dist/textarea.test.js +77 -0
  269. package/dist/textarea.test.js.map +1 -0
  270. package/dist/time.d.ts +93 -0
  271. package/dist/time.d.ts.map +1 -0
  272. package/dist/time.js +181 -0
  273. package/dist/time.js.map +1 -0
  274. package/dist/time.test.d.ts +2 -0
  275. package/dist/time.test.d.ts.map +1 -0
  276. package/dist/time.test.js +159 -0
  277. package/dist/time.test.js.map +1 -0
  278. package/dist/toast.d.ts +60 -0
  279. package/dist/toast.d.ts.map +1 -0
  280. package/dist/toast.js +135 -0
  281. package/dist/toast.js.map +1 -0
  282. package/dist/toast.test.d.ts +2 -0
  283. package/dist/toast.test.d.ts.map +1 -0
  284. package/dist/toast.test.js +127 -0
  285. package/dist/toast.test.js.map +1 -0
  286. package/dist/tree.d.ts +129 -0
  287. package/dist/tree.d.ts.map +1 -0
  288. package/dist/tree.js +351 -0
  289. package/dist/tree.js.map +1 -0
  290. package/dist/tree.test.d.ts +2 -0
  291. package/dist/tree.test.d.ts.map +1 -0
  292. package/dist/tree.test.js +291 -0
  293. package/dist/tree.test.js.map +1 -0
  294. package/dist/upload.d.ts +62 -0
  295. package/dist/upload.d.ts.map +1 -0
  296. package/dist/upload.js +85 -0
  297. package/dist/upload.js.map +1 -0
  298. package/dist/upload.test.d.ts +2 -0
  299. package/dist/upload.test.d.ts.map +1 -0
  300. package/dist/upload.test.js +169 -0
  301. package/dist/upload.test.js.map +1 -0
  302. package/dist/virtual-list.d.ts +83 -0
  303. package/dist/virtual-list.d.ts.map +1 -0
  304. package/dist/virtual-list.js +143 -0
  305. package/dist/virtual-list.js.map +1 -0
  306. package/dist/virtual-list.test.d.ts +2 -0
  307. package/dist/virtual-list.test.d.ts.map +1 -0
  308. package/dist/virtual-list.test.js +148 -0
  309. package/dist/virtual-list.test.js.map +1 -0
  310. package/package.json +22 -0
@@ -0,0 +1,223 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { computeVisibleCount, computeOverflowPartition, applyHysteresis, computeTabOverflow, } from './overflow-list.js';
3
+ // five items, each 100px wide, gap 0 for easy arithmetic
4
+ const sizes = [100, 100, 100, 100, 100];
5
+ describe('computeVisibleCount', () => {
6
+ it('shows everything when it all fits', () => {
7
+ expect(computeVisibleCount({ itemSizes: sizes, containerSize: 500, overflowSize: 40, gap: 0 })).toEqual({
8
+ visibleCount: 5,
9
+ overflowCount: 0,
10
+ });
11
+ // exact fit
12
+ expect(computeVisibleCount({ itemSizes: sizes, containerSize: 500, overflowSize: 40, gap: 0 }).overflowCount).toBe(0);
13
+ });
14
+ it('collapses when one px short, reserving the overflow node', () => {
15
+ // 499 < 500 total → must collapse; reserve 40 for overflow node.
16
+ // fit n items with +40: n=4 → 400+40=440 ≤ 499 ✓ ; n=5 not needed (collapse path)
17
+ const r = computeVisibleCount({ itemSizes: sizes, containerSize: 499, overflowSize: 40, gap: 0 });
18
+ expect(r).toEqual({ visibleCount: 4, overflowCount: 1 });
19
+ });
20
+ it('accounts for gaps', () => {
21
+ // container 360, gap 10, overflow 40. all: 5*100+4*10=540 > 360 → collapse.
22
+ // n items + reserved(40+10): n=2 → 200+10 +50 =260 ≤360 ; n=3 →300+20+50=370 >360 → visible 2
23
+ const r = computeVisibleCount({ itemSizes: sizes, containerSize: 360, overflowSize: 40, gap: 10 });
24
+ expect(r).toEqual({ visibleCount: 2, overflowCount: 3 });
25
+ });
26
+ it('handles total overflow (nothing fits with overflow node) → at least 0', () => {
27
+ const r = computeVisibleCount({ itemSizes: sizes, containerSize: 50, overflowSize: 40, gap: 0 });
28
+ expect(r.visibleCount).toBe(0);
29
+ expect(r.overflowCount).toBe(5);
30
+ });
31
+ it('respects minVisibleItems (prefer overflow row over hiding too much)', () => {
32
+ const r = computeVisibleCount({
33
+ itemSizes: sizes,
34
+ containerSize: 150,
35
+ overflowSize: 40,
36
+ gap: 0,
37
+ minVisibleItems: 3,
38
+ });
39
+ expect(r.visibleCount).toBe(3);
40
+ expect(r.overflowCount).toBe(2);
41
+ });
42
+ it('respects alwaysVisible indexes', () => {
43
+ // container only fits 1 normally, but index 2 must stay visible → floor to 3
44
+ const r = computeVisibleCount({
45
+ itemSizes: sizes,
46
+ containerSize: 150,
47
+ overflowSize: 40,
48
+ gap: 0,
49
+ alwaysVisible: [2],
50
+ });
51
+ expect(r.visibleCount).toBe(3);
52
+ });
53
+ it('floor that covers all items removes overflow', () => {
54
+ const r = computeVisibleCount({
55
+ itemSizes: sizes,
56
+ containerSize: 150,
57
+ overflowSize: 40,
58
+ gap: 0,
59
+ minVisibleItems: 5,
60
+ });
61
+ expect(r).toEqual({ visibleCount: 5, overflowCount: 0 });
62
+ });
63
+ it('empty input', () => {
64
+ expect(computeVisibleCount({ itemSizes: [], containerSize: 500, overflowSize: 40, gap: 0 })).toEqual({
65
+ visibleCount: 0,
66
+ overflowCount: 0,
67
+ });
68
+ });
69
+ });
70
+ describe('computeOverflowPartition', () => {
71
+ it('end (default): collapses trailing items, leading stay visible', () => {
72
+ // 360, gap 10, overflow 40 → 2 leading fit (same math as computeVisibleCount)
73
+ const r = computeOverflowPartition({
74
+ itemSizes: sizes,
75
+ containerSize: 360,
76
+ overflowSize: 40,
77
+ gap: 10,
78
+ });
79
+ expect(r).toEqual({
80
+ visibleCount: 2,
81
+ overflowCount: 3,
82
+ visibleIndexes: [0, 1],
83
+ overflowIndexes: [2, 3, 4],
84
+ });
85
+ });
86
+ it('start: collapses leading items, trailing stay visible', () => {
87
+ // same fit (2 items), but kept window is the *last* two → [3,4] visible
88
+ const r = computeOverflowPartition({
89
+ itemSizes: sizes,
90
+ containerSize: 360,
91
+ overflowSize: 40,
92
+ gap: 10,
93
+ collapseFrom: 'start',
94
+ });
95
+ expect(r).toEqual({
96
+ visibleCount: 2,
97
+ overflowCount: 3,
98
+ visibleIndexes: [3, 4],
99
+ overflowIndexes: [0, 1, 2],
100
+ });
101
+ });
102
+ it('start: uneven sizes fit from the tail, not the head', () => {
103
+ // tail two are tiny, head three are huge. container only fits the tail.
104
+ // sizes reversed = [20,20,300,300,300]; container 60 gap 10 overflow 40:
105
+ // reserved 50; n=1 →20+50=70>60 → 0? use container 80: n=1→20+50=70≤80, n=2→20+20+10+50=100>80 → 1 visible.
106
+ const r = computeOverflowPartition({
107
+ itemSizes: [300, 300, 300, 20, 20],
108
+ containerSize: 80,
109
+ overflowSize: 40,
110
+ gap: 10,
111
+ collapseFrom: 'start',
112
+ });
113
+ expect(r.visibleCount).toBe(1);
114
+ expect(r.visibleIndexes).toEqual([4]);
115
+ expect(r.overflowIndexes).toEqual([0, 1, 2, 3]);
116
+ });
117
+ it('start: mirrors alwaysVisible indexes (index 0 must stay → floor)', () => {
118
+ // only 1 fits normally, but index 0 must stay visible. mirrored → keeps a
119
+ // window large enough to include index 0, i.e. all items visible.
120
+ const r = computeOverflowPartition({
121
+ itemSizes: sizes,
122
+ containerSize: 150,
123
+ overflowSize: 40,
124
+ gap: 0,
125
+ collapseFrom: 'start',
126
+ alwaysVisible: [0],
127
+ });
128
+ expect(r.visibleIndexes).toContain(0);
129
+ expect(r.visibleCount).toBe(5);
130
+ });
131
+ it('respects minVisibleItems in start mode', () => {
132
+ const r = computeOverflowPartition({
133
+ itemSizes: sizes,
134
+ containerSize: 150,
135
+ overflowSize: 40,
136
+ gap: 0,
137
+ collapseFrom: 'start',
138
+ minVisibleItems: 3,
139
+ });
140
+ expect(r.visibleCount).toBe(3);
141
+ expect(r.visibleIndexes).toEqual([2, 3, 4]);
142
+ expect(r.overflowIndexes).toEqual([0, 1]);
143
+ });
144
+ it('everything fits → no overflow, both directions', () => {
145
+ const end = computeOverflowPartition({
146
+ itemSizes: sizes,
147
+ containerSize: 500,
148
+ overflowSize: 40,
149
+ gap: 0,
150
+ });
151
+ const start = computeOverflowPartition({
152
+ itemSizes: sizes,
153
+ containerSize: 500,
154
+ overflowSize: 40,
155
+ gap: 0,
156
+ collapseFrom: 'start',
157
+ });
158
+ expect(end.visibleIndexes).toEqual([0, 1, 2, 3, 4]);
159
+ expect(start.visibleIndexes).toEqual([0, 1, 2, 3, 4]);
160
+ expect(end.overflowCount).toBe(0);
161
+ expect(start.overflowCount).toBe(0);
162
+ });
163
+ it('empty input', () => {
164
+ const r = computeOverflowPartition({
165
+ itemSizes: [],
166
+ containerSize: 500,
167
+ overflowSize: 40,
168
+ gap: 0,
169
+ collapseFrom: 'start',
170
+ });
171
+ expect(r).toEqual({
172
+ visibleCount: 0,
173
+ overflowCount: 0,
174
+ visibleIndexes: [],
175
+ overflowIndexes: [],
176
+ });
177
+ });
178
+ });
179
+ describe('applyHysteresis', () => {
180
+ it('keeps more items visible inside the dead-band', () => {
181
+ // container wobbled by 5px (≤ threshold 8); next would collapse to 3, prev was 4 → keep 4
182
+ expect(applyHysteresis(4, 3, 500, 495, 8)).toBe(4);
183
+ });
184
+ it('applies the new count for a real resize beyond threshold', () => {
185
+ expect(applyHysteresis(4, 2, 500, 400, 8)).toBe(2);
186
+ });
187
+ it('no change when next equals prev', () => {
188
+ expect(applyHysteresis(4, 4, 500, 498, 8)).toBe(4);
189
+ });
190
+ });
191
+ describe('computeTabOverflow', () => {
192
+ it('shows all tabs when everything fits', () => {
193
+ expect(computeTabOverflow({ tabSizes: sizes, containerSize: 500, moreSize: 40, gap: 0 })).toEqual({ visibleIndexes: [0, 1, 2, 3, 4], overflowIndexes: [] });
194
+ });
195
+ it('collapses trailing tabs into overflow when short', () => {
196
+ // 360, gap 10, more 40 → 2 leading fit (same math as computeVisibleCount)
197
+ expect(computeTabOverflow({ tabSizes: sizes, containerSize: 360, moreSize: 40, gap: 10 })).toEqual({ visibleIndexes: [0, 1], overflowIndexes: [2, 3, 4] });
198
+ });
199
+ it('keeps the active tab visible by swapping it into the last visible slot', () => {
200
+ // Only 2 leading tabs fit; active is index 4 (would overflow). Swap: drop
201
+ // last visible (index 1), surface index 4 → visible {0,4}.
202
+ expect(computeTabOverflow({
203
+ tabSizes: sizes,
204
+ containerSize: 360,
205
+ moreSize: 40,
206
+ gap: 10,
207
+ activeIndex: 4,
208
+ })).toEqual({ visibleIndexes: [0, 4], overflowIndexes: [1, 2, 3] });
209
+ });
210
+ it('does not swap when the active tab is already visible', () => {
211
+ expect(computeTabOverflow({
212
+ tabSizes: sizes,
213
+ containerSize: 360,
214
+ moreSize: 40,
215
+ gap: 10,
216
+ activeIndex: 0,
217
+ })).toEqual({ visibleIndexes: [0, 1], overflowIndexes: [2, 3, 4] });
218
+ });
219
+ it('handles empty input', () => {
220
+ expect(computeTabOverflow({ tabSizes: [], containerSize: 500, moreSize: 40, gap: 0 })).toEqual({ visibleIndexes: [], overflowIndexes: [] });
221
+ });
222
+ });
223
+ //# sourceMappingURL=overflow-list.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overflow-list.test.js","sourceRoot":"","sources":["../src/overflow-list.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Pagination helpers — framework-agnostic page-count and boundary clamping.
3
+ * Pure functions only; the render layer owns state, onChange dispatch and DOM.
4
+ * See specs/components/navigation/Pagination.spec.md.
5
+ */
6
+ /** Total page count for `total` items at `pageSize` per page. Always >= 1. */
7
+ export declare function pageCount(total: number, pageSize: number): number;
8
+ /**
9
+ * Clamp a page number into the valid range [1, pageCount(total, pageSize)].
10
+ * Non-finite / non-integer input falls back to page 1 (lower bound).
11
+ */
12
+ export declare function clampPage(page: number, total: number, pageSize: number): number;
13
+ /** True when `page` is already a valid in-range page for the given dataset. */
14
+ export declare function isPageInRange(page: number, total: number, pageSize: number): boolean;
15
+ /**
16
+ * Resolve a page-size value: keep it when it is a positive finite number that
17
+ * appears in `options`; otherwise fall back to `fallback`. Used to guard the
18
+ * size-changer / pageSize prop against invalid values.
19
+ */
20
+ export declare function clampPageSize(size: number, options: number[], fallback: number): number;
21
+ /** A cell in the rendered page sequence: a concrete page or an ellipsis gap. */
22
+ export type PageCell = {
23
+ type: 'page';
24
+ value: number;
25
+ } | {
26
+ type: 'ellipsis';
27
+ position: 'prev' | 'next';
28
+ };
29
+ /**
30
+ * Build the visible page sequence with ellipsis folding (AntD-style).
31
+ *
32
+ * Always keeps `boundaryCount` pages at each end and `siblingCount` pages on
33
+ * either side of `current`; everything else collapses into an ellipsis cell.
34
+ * An ellipsis is only emitted when it would hide at least two pages — when a
35
+ * single page would be hidden it is rendered instead (no `… ` standing in for
36
+ * one page). The result length is bounded and independent of `count` once it
37
+ * exceeds the visible window, so a million pages still yields O(1) cells.
38
+ *
39
+ * Pure function of `(current, count, siblingCount, boundaryCount)` — safe to
40
+ * call from the render layer / memoize. Inputs are sanitised: non-finite or
41
+ * negative sibling/boundary counts fall back to 0, `current` is clamped into
42
+ * `[1, count]`, `count` is floored at 1.
43
+ */
44
+ export declare function pageRange(current: number, count: number, siblingCount?: number, boundaryCount?: number): PageCell[];
45
+ /**
46
+ * Parse + clamp a quick-jumper text input into a valid page number.
47
+ * Returns the clamped page, or `null` when the input is empty / non-numeric
48
+ * (caller decides whether to ignore or surface a warning).
49
+ */
50
+ export declare function parseJumpInput(raw: string, total: number, pageSize: number): number | null;
51
+ //# sourceMappingURL=pagination.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../src/pagination.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIjE;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO/E;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGpF;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKvF;AAED,gFAAgF;AAChF,MAAM,MAAM,QAAQ,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC;AAEpD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,YAAY,SAAI,EAChB,aAAa,SAAI,GAChB,QAAQ,EAAE,CAmDZ;AAUD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,MAAM,GAAG,IAAI,CAOf"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Pagination helpers — framework-agnostic page-count and boundary clamping.
3
+ * Pure functions only; the render layer owns state, onChange dispatch and DOM.
4
+ * See specs/components/navigation/Pagination.spec.md.
5
+ */
6
+ /** Total page count for `total` items at `pageSize` per page. Always >= 1. */
7
+ export function pageCount(total, pageSize) {
8
+ if (!Number.isFinite(total) || total <= 0)
9
+ return 1;
10
+ if (!Number.isFinite(pageSize) || pageSize <= 0)
11
+ return 1;
12
+ return Math.max(1, Math.ceil(total / pageSize));
13
+ }
14
+ /**
15
+ * Clamp a page number into the valid range [1, pageCount(total, pageSize)].
16
+ * Non-finite / non-integer input falls back to page 1 (lower bound).
17
+ */
18
+ export function clampPage(page, total, pageSize) {
19
+ const count = pageCount(total, pageSize);
20
+ if (!Number.isFinite(page))
21
+ return 1;
22
+ const intPage = Math.trunc(page);
23
+ if (intPage < 1)
24
+ return 1;
25
+ if (intPage > count)
26
+ return count;
27
+ return intPage;
28
+ }
29
+ /** True when `page` is already a valid in-range page for the given dataset. */
30
+ export function isPageInRange(page, total, pageSize) {
31
+ if (!Number.isInteger(page))
32
+ return false;
33
+ return page >= 1 && page <= pageCount(total, pageSize);
34
+ }
35
+ /**
36
+ * Resolve a page-size value: keep it when it is a positive finite number that
37
+ * appears in `options`; otherwise fall back to `fallback`. Used to guard the
38
+ * size-changer / pageSize prop against invalid values.
39
+ */
40
+ export function clampPageSize(size, options, fallback) {
41
+ if (!Number.isFinite(size) || size <= 0)
42
+ return fallback;
43
+ const intSize = Math.trunc(size);
44
+ if (options.length > 0 && !options.includes(intSize))
45
+ return fallback;
46
+ return intSize;
47
+ }
48
+ /**
49
+ * Build the visible page sequence with ellipsis folding (AntD-style).
50
+ *
51
+ * Always keeps `boundaryCount` pages at each end and `siblingCount` pages on
52
+ * either side of `current`; everything else collapses into an ellipsis cell.
53
+ * An ellipsis is only emitted when it would hide at least two pages — when a
54
+ * single page would be hidden it is rendered instead (no `… ` standing in for
55
+ * one page). The result length is bounded and independent of `count` once it
56
+ * exceeds the visible window, so a million pages still yields O(1) cells.
57
+ *
58
+ * Pure function of `(current, count, siblingCount, boundaryCount)` — safe to
59
+ * call from the render layer / memoize. Inputs are sanitised: non-finite or
60
+ * negative sibling/boundary counts fall back to 0, `current` is clamped into
61
+ * `[1, count]`, `count` is floored at 1.
62
+ */
63
+ export function pageRange(current, count, siblingCount = 1, boundaryCount = 1) {
64
+ const total = Math.max(1, Number.isFinite(count) ? Math.trunc(count) : 1);
65
+ const sibling = Math.max(0, Number.isFinite(siblingCount) ? Math.trunc(siblingCount) : 0);
66
+ const boundary = Math.max(0, Number.isFinite(boundaryCount) ? Math.trunc(boundaryCount) : 0);
67
+ const cur = Math.min(Math.max(1, Number.isFinite(current) ? Math.trunc(current) : 1), total);
68
+ // When every page fits inside the visible window there is nothing to fold:
69
+ // list them all. Window width = boundary*2 + sibling*2 + current + 2 ellipsis.
70
+ if (boundary * 2 + sibling * 2 + 5 >= total) {
71
+ return numbers(1, total).map((value) => ({ type: 'page', value }));
72
+ }
73
+ // Fixed-size leading / trailing boundary blocks (capped at total).
74
+ const startPages = numbers(1, Math.min(boundary, total));
75
+ const endPages = numbers(Math.max(total - boundary + 1, boundary + 1), total);
76
+ // Sibling window around current, kept clamped so it never overlaps the
77
+ // boundary blocks and keeps a constant width even at the very ends.
78
+ const siblingsStart = Math.max(Math.min(cur - sibling, total - boundary - sibling * 2 - 1), boundary + 2);
79
+ const firstEndPage = endPages[0];
80
+ const siblingsEnd = Math.min(Math.max(cur + sibling, boundary + sibling * 2 + 2), firstEndPage !== undefined ? firstEndPage - 2 : total - 1);
81
+ const items = [
82
+ ...startPages,
83
+ // left ellipsis, or the single page it would have hidden
84
+ ...(siblingsStart > boundary + 2
85
+ ? ['ellipsis-prev']
86
+ : boundary + 1 < siblingsStart
87
+ ? numbers(boundary + 1, siblingsStart - 1)
88
+ : []),
89
+ ...numbers(siblingsStart, siblingsEnd),
90
+ // right ellipsis, or the single page it would have hidden
91
+ ...(siblingsEnd < total - boundary - 1
92
+ ? ['ellipsis-next']
93
+ : total - boundary > siblingsEnd
94
+ ? numbers(siblingsEnd + 1, total - boundary)
95
+ : []),
96
+ ...endPages,
97
+ ];
98
+ return items.map((it) => typeof it === 'number'
99
+ ? { type: 'page', value: it }
100
+ : { type: 'ellipsis', position: it === 'ellipsis-prev' ? 'prev' : 'next' });
101
+ }
102
+ /** Inclusive integer range `[start, end]`; empty when `start > end`. */
103
+ function numbers(start, end) {
104
+ if (start > end)
105
+ return [];
106
+ const out = [];
107
+ for (let i = start; i <= end; i++)
108
+ out.push(i);
109
+ return out;
110
+ }
111
+ /**
112
+ * Parse + clamp a quick-jumper text input into a valid page number.
113
+ * Returns the clamped page, or `null` when the input is empty / non-numeric
114
+ * (caller decides whether to ignore or surface a warning).
115
+ */
116
+ export function parseJumpInput(raw, total, pageSize) {
117
+ const trimmed = raw.trim();
118
+ if (trimmed === '')
119
+ return null;
120
+ if (!/^[+-]?\d+$/.test(trimmed))
121
+ return null;
122
+ const n = Number.parseInt(trimmed, 10);
123
+ if (Number.isNaN(n))
124
+ return null;
125
+ return clampPage(n, total, pageSize);
126
+ }
127
+ //# sourceMappingURL=pagination.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.js","sourceRoot":"","sources":["../src/pagination.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pagination.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.test.d.ts","sourceRoot":"","sources":["../src/pagination.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,147 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { pageCount, clampPage, isPageInRange, clampPageSize, parseJumpInput, pageRange, } from './pagination.js';
3
+ /** Compact a PageCell[] into a readable token list, e.g. [1,'<',5,'>',10]. */
4
+ function tokens(cells) {
5
+ return cells.map((c) => (c.type === 'page' ? c.value : c.position === 'prev' ? '<' : '>'));
6
+ }
7
+ describe('pageCount', () => {
8
+ it('computes ceil(total / pageSize)', () => {
9
+ expect(pageCount(100, 10)).toBe(10);
10
+ expect(pageCount(101, 10)).toBe(11);
11
+ expect(pageCount(5, 10)).toBe(1);
12
+ });
13
+ it('is always at least 1', () => {
14
+ expect(pageCount(0, 10)).toBe(1);
15
+ expect(pageCount(-5, 10)).toBe(1);
16
+ });
17
+ it('guards invalid pageSize', () => {
18
+ expect(pageCount(100, 0)).toBe(1);
19
+ expect(pageCount(100, -10)).toBe(1);
20
+ expect(pageCount(100, Number.NaN)).toBe(1);
21
+ expect(pageCount(Number.POSITIVE_INFINITY, 10)).toBe(1);
22
+ });
23
+ });
24
+ describe('clampPage', () => {
25
+ it('returns the page unchanged when in range', () => {
26
+ expect(clampPage(3, 100, 10)).toBe(3);
27
+ expect(clampPage(1, 100, 10)).toBe(1);
28
+ expect(clampPage(10, 100, 10)).toBe(10);
29
+ });
30
+ it('clamps below the lower bound to 1', () => {
31
+ expect(clampPage(0, 100, 10)).toBe(1);
32
+ expect(clampPage(-5, 100, 10)).toBe(1);
33
+ });
34
+ it('clamps above the upper bound to the last page', () => {
35
+ expect(clampPage(11, 100, 10)).toBe(10);
36
+ expect(clampPage(999, 100, 10)).toBe(10);
37
+ });
38
+ it('truncates non-integers', () => {
39
+ expect(clampPage(3.9, 100, 10)).toBe(3);
40
+ });
41
+ it('falls back to 1 on non-finite input', () => {
42
+ expect(clampPage(Number.NaN, 100, 10)).toBe(1);
43
+ expect(clampPage(Number.POSITIVE_INFINITY, 100, 10)).toBe(1);
44
+ expect(clampPage(Number.NEGATIVE_INFINITY, 100, 10)).toBe(1);
45
+ });
46
+ it('handles empty datasets (always page 1)', () => {
47
+ expect(clampPage(5, 0, 10)).toBe(1);
48
+ });
49
+ });
50
+ describe('isPageInRange', () => {
51
+ it('flips at the boundaries', () => {
52
+ expect(isPageInRange(0, 100, 10)).toBe(false);
53
+ expect(isPageInRange(1, 100, 10)).toBe(true);
54
+ expect(isPageInRange(10, 100, 10)).toBe(true);
55
+ expect(isPageInRange(11, 100, 10)).toBe(false);
56
+ });
57
+ it('rejects non-integers', () => {
58
+ expect(isPageInRange(3.5, 100, 10)).toBe(false);
59
+ expect(isPageInRange(Number.NaN, 100, 10)).toBe(false);
60
+ });
61
+ });
62
+ describe('clampPageSize', () => {
63
+ const opts = [10, 20, 50, 100];
64
+ it('keeps a valid option', () => {
65
+ expect(clampPageSize(20, opts, 10)).toBe(20);
66
+ });
67
+ it('falls back when not in options', () => {
68
+ expect(clampPageSize(7, opts, 10)).toBe(10);
69
+ });
70
+ it('falls back on invalid values', () => {
71
+ expect(clampPageSize(0, opts, 10)).toBe(10);
72
+ expect(clampPageSize(-5, opts, 10)).toBe(10);
73
+ expect(clampPageSize(Number.NaN, opts, 10)).toBe(10);
74
+ });
75
+ it('allows any positive value when options is empty', () => {
76
+ expect(clampPageSize(7, [], 10)).toBe(7);
77
+ expect(clampPageSize(0, [], 10)).toBe(10);
78
+ });
79
+ });
80
+ describe('parseJumpInput', () => {
81
+ it('parses and returns an in-range page', () => {
82
+ expect(parseJumpInput('3', 100, 10)).toBe(3);
83
+ });
84
+ it('clamps out-of-range input', () => {
85
+ expect(parseJumpInput('999', 100, 10)).toBe(10);
86
+ expect(parseJumpInput('0', 100, 10)).toBe(1);
87
+ expect(parseJumpInput('-5', 100, 10)).toBe(1);
88
+ });
89
+ it('returns null for empty / non-numeric input', () => {
90
+ expect(parseJumpInput('', 100, 10)).toBeNull();
91
+ expect(parseJumpInput(' ', 100, 10)).toBeNull();
92
+ expect(parseJumpInput('abc', 100, 10)).toBeNull();
93
+ expect(parseJumpInput('1.5', 100, 10)).toBeNull();
94
+ expect(parseJumpInput('3px', 100, 10)).toBeNull();
95
+ });
96
+ it('trims surrounding whitespace', () => {
97
+ expect(parseJumpInput(' 4 ', 100, 10)).toBe(4);
98
+ });
99
+ });
100
+ describe('pageRange', () => {
101
+ it('lists every page when the window covers them (no ellipsis)', () => {
102
+ // default sibling=1, boundary=1 → list all when count <= 9
103
+ expect(tokens(pageRange(1, 7))).toEqual([1, 2, 3, 4, 5, 6, 7]);
104
+ expect(tokens(pageRange(3, 5))).toEqual([1, 2, 3, 4, 5]);
105
+ expect(tokens(pageRange(1, 1))).toEqual([1]);
106
+ });
107
+ it('folds the right side when current is near the start', () => {
108
+ expect(tokens(pageRange(1, 10))).toEqual([1, 2, 3, 4, 5, '>', 10]);
109
+ expect(tokens(pageRange(3, 10))).toEqual([1, 2, 3, 4, 5, '>', 10]);
110
+ });
111
+ it('folds the left side when current is near the end', () => {
112
+ expect(tokens(pageRange(10, 10))).toEqual([1, '<', 6, 7, 8, 9, 10]);
113
+ expect(tokens(pageRange(8, 10))).toEqual([1, '<', 6, 7, 8, 9, 10]);
114
+ });
115
+ it('folds both sides when current is in the middle', () => {
116
+ expect(tokens(pageRange(5, 10))).toEqual([1, '<', 4, 5, 6, '>', 10]);
117
+ expect(tokens(pageRange(50, 100))).toEqual([1, '<', 49, 50, 51, '>', 100]);
118
+ });
119
+ it('never renders an ellipsis that would hide only one page', () => {
120
+ // gap between boundary(1) and sibling window would be a single page → show it
121
+ expect(tokens(pageRange(4, 10))).toEqual([1, 2, 3, 4, 5, '>', 10]);
122
+ expect(tokens(pageRange(7, 10))).toEqual([1, '<', 6, 7, 8, 9, 10]);
123
+ });
124
+ it('honours siblingCount', () => {
125
+ // wider window keeps the left side contiguous (no left ellipsis needed)
126
+ expect(tokens(pageRange(5, 20, 2))).toEqual([1, 2, 3, 4, 5, 6, 7, '>', 20]);
127
+ expect(tokens(pageRange(10, 20, 2))).toEqual([1, '<', 8, 9, 10, 11, 12, '>', 20]);
128
+ expect(tokens(pageRange(5, 20, 0))).toEqual([1, '<', 5, '>', 20]);
129
+ });
130
+ it('honours boundaryCount', () => {
131
+ expect(tokens(pageRange(10, 20, 1, 2))).toEqual([1, 2, '<', 9, 10, 11, '>', 19, 20]);
132
+ expect(tokens(pageRange(10, 20, 1, 0))).toEqual(['<', 9, 10, 11, '>']);
133
+ });
134
+ it('keeps cell count O(1) regardless of total pages', () => {
135
+ const small = pageRange(500_000, 1_000_000);
136
+ const huge = pageRange(500_000, 1_000_000_000);
137
+ expect(small.length).toBe(huge.length);
138
+ expect(tokens(small)).toEqual([1, '<', 499999, 500000, 500001, '>', 1000000]);
139
+ });
140
+ it('sanitises invalid inputs', () => {
141
+ expect(tokens(pageRange(Number.NaN, 10))).toEqual([1, 2, 3, 4, 5, '>', 10]); // current→1
142
+ expect(tokens(pageRange(99, 10))).toEqual([1, '<', 6, 7, 8, 9, 10]); // current clamped to 10
143
+ expect(tokens(pageRange(5, 10, -1, -1))).toEqual(['<', 5, '>']); // sibling/boundary→0
144
+ expect(tokens(pageRange(1, 0))).toEqual([1]); // count floored to 1
145
+ });
146
+ });
147
+ //# sourceMappingURL=pagination.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.test.js","sourceRoot":"","sources":["../src/pagination.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,SAAS,EACT,SAAS,EACT,aAAa,EACb,aAAa,EACb,cAAc,EACd,SAAS,GAEV,MAAM,iBAAiB,CAAC;AAEzB,8EAA8E;AAC9E,SAAS,MAAM,CAAC,KAAiB;IAC/B,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpC,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxC,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,iBAAiB,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7D,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,iBAAiB,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,MAAM,IAAI,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;IAE/B,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7C,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChD,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,CAAC,cAAc,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC/C,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAClD,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAClD,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAClD,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,2DAA2D;QAC3D,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/D,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;QACnE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACpE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;QACrE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,8EAA8E;QAC9E,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;QACnE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,wEAAwE;QACxE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;QAC5E,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;QAClF,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QACrF,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAC5C,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QAC/C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY;QACzF,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,wBAAwB;QAC7F,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,qBAAqB;QACtF,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,qBAAqB;IACrE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}