panelui-native 0.98.0 → 0.100.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 (41) hide show
  1. package/lib/module/components/animated-badge/index.js +24 -2
  2. package/lib/module/components/animated-badge/index.js.map +1 -1
  3. package/lib/module/components/bump-chart/index.js +1236 -0
  4. package/lib/module/components/bump-chart/index.js.map +1 -0
  5. package/lib/module/components/image-viewer/image-viewer-geometry.js +203 -0
  6. package/lib/module/components/image-viewer/image-viewer-geometry.js.map +1 -0
  7. package/lib/module/components/image-viewer/index.js +1100 -0
  8. package/lib/module/components/image-viewer/index.js.map +1 -0
  9. package/lib/module/components/mirror-area-chart/index.js +1113 -0
  10. package/lib/module/components/mirror-area-chart/index.js.map +1 -0
  11. package/lib/module/index.js +3 -0
  12. package/lib/module/index.js.map +1 -1
  13. package/lib/module/primitives/scrim.js +65 -1
  14. package/lib/module/primitives/scrim.js.map +1 -1
  15. package/lib/module/utils/chart.js +70 -0
  16. package/lib/module/utils/chart.js.map +1 -1
  17. package/lib/typescript/src/components/animated-badge/index.d.ts +5 -0
  18. package/lib/typescript/src/components/animated-badge/index.d.ts.map +1 -1
  19. package/lib/typescript/src/components/bump-chart/index.d.ts +267 -0
  20. package/lib/typescript/src/components/bump-chart/index.d.ts.map +1 -0
  21. package/lib/typescript/src/components/image-viewer/image-viewer-geometry.d.ts +83 -0
  22. package/lib/typescript/src/components/image-viewer/image-viewer-geometry.d.ts.map +1 -0
  23. package/lib/typescript/src/components/image-viewer/index.d.ts +148 -0
  24. package/lib/typescript/src/components/image-viewer/index.d.ts.map +1 -0
  25. package/lib/typescript/src/components/mirror-area-chart/index.d.ts +263 -0
  26. package/lib/typescript/src/components/mirror-area-chart/index.d.ts.map +1 -0
  27. package/lib/typescript/src/index.d.ts +3 -0
  28. package/lib/typescript/src/index.d.ts.map +1 -1
  29. package/lib/typescript/src/primitives/scrim.d.ts +11 -1
  30. package/lib/typescript/src/primitives/scrim.d.ts.map +1 -1
  31. package/lib/typescript/src/utils/chart.d.ts +23 -0
  32. package/lib/typescript/src/utils/chart.d.ts.map +1 -1
  33. package/package.json +1 -1
  34. package/src/components/animated-badge/index.tsx +35 -2
  35. package/src/components/bump-chart/index.tsx +1455 -0
  36. package/src/components/image-viewer/image-viewer-geometry.ts +205 -0
  37. package/src/components/image-viewer/index.tsx +1329 -0
  38. package/src/components/mirror-area-chart/index.tsx +1333 -0
  39. package/src/index.ts +42 -0
  40. package/src/primitives/scrim.tsx +96 -1
  41. package/src/utils/chart.ts +70 -0
@@ -0,0 +1,205 @@
1
+ /**
2
+ * The arithmetic behind the image viewer, kept apart from the component.
3
+ *
4
+ * Every function here runs on the UI thread inside a gesture or an animated
5
+ * style, so each is a worklet. None of them touches React Native, which is what
6
+ * lets the contract tests run them in Node.
7
+ */
8
+
9
+ export interface Size {
10
+ width: number;
11
+ height: number;
12
+ }
13
+
14
+ export interface Rect extends Size {
15
+ x: number;
16
+ y: number;
17
+ }
18
+
19
+ /** How much a rubber-banded overshoot gives. Lower is stiffer. */
20
+ export const RUBBER_BAND = 0.55;
21
+
22
+ export function clamp(value: number, min: number, max: number): number {
23
+ 'worklet';
24
+ return Math.min(Math.max(value, min), max);
25
+ }
26
+
27
+ export function lerp(from: number, to: number, t: number): number {
28
+ 'worklet';
29
+ return from + (to - from) * t;
30
+ }
31
+
32
+ export function lerpRect(from: Rect, to: Rect, t: number): Rect {
33
+ 'worklet';
34
+ return {
35
+ x: lerp(from.x, to.x, t),
36
+ y: lerp(from.y, to.y, t),
37
+ width: lerp(from.width, to.width, t),
38
+ height: lerp(from.height, to.height, t),
39
+ };
40
+ }
41
+
42
+ /**
43
+ * The largest rect with the image's proportions that fits inside the box,
44
+ * centred in it. An image with no known size fills the box.
45
+ */
46
+ export function fitContain(image: Size, box: Size): Rect {
47
+ 'worklet';
48
+ if (image.width <= 0 || image.height <= 0) {
49
+ return { x: 0, y: 0, width: box.width, height: box.height };
50
+ }
51
+ const scale = Math.min(box.width / image.width, box.height / image.height);
52
+ const width = image.width * scale;
53
+ const height = image.height * scale;
54
+ return { x: (box.width - width) / 2, y: (box.height - height) / 2, width, height };
55
+ }
56
+
57
+ /** `fitContain` inside a rect that does not start at the origin. */
58
+ export function fitWithin(image: Size, box: Rect): Rect {
59
+ 'worklet';
60
+ const fitted = fitContain(image, box);
61
+ return { ...fitted, x: box.x + fitted.x, y: box.y + fitted.y };
62
+ }
63
+
64
+ /**
65
+ * The smallest size with the image's proportions that covers the frame.
66
+ *
67
+ * A thumbnail crops its picture to its box; the viewer shows the whole of it.
68
+ * Drawing the image at this size inside a frame that grows from one to the
69
+ * other is what makes the crop open out instead of the picture jumping.
70
+ */
71
+ export function coverSize(image: Size, frame: Size): Size {
72
+ 'worklet';
73
+ if (image.width <= 0 || image.height <= 0) {
74
+ return { width: frame.width, height: frame.height };
75
+ }
76
+ const scale = Math.max(frame.width / image.width, frame.height / image.height);
77
+ return { width: image.width * scale, height: image.height * scale };
78
+ }
79
+
80
+ /**
81
+ * How far past its limit a value is allowed to travel, given how far it was
82
+ * pushed. The resistance grows with the push and never quite reaches `dimension`.
83
+ */
84
+ export function rubberBand(overshoot: number, dimension: number, coefficient?: number): number {
85
+ 'worklet';
86
+ if (dimension <= 0) return 0;
87
+ const give = coefficient ?? RUBBER_BAND;
88
+ return (1 - 1 / ((overshoot * give) / dimension + 1)) * dimension;
89
+ }
90
+
91
+ /** Clamps to `[min, max]`, letting the value stretch past either end with resistance. */
92
+ export function rubberBandClamp(
93
+ value: number,
94
+ min: number,
95
+ max: number,
96
+ dimension: number,
97
+ coefficient?: number
98
+ ): number {
99
+ 'worklet';
100
+ const clamped = clamp(value, min, max);
101
+ const overshoot = Math.abs(value - clamped);
102
+ if (overshoot === 0) return clamped;
103
+ const sign = value < clamped ? -1 : 1;
104
+ return clamped + sign * rubberBand(overshoot, dimension, coefficient);
105
+ }
106
+
107
+ /**
108
+ * How far a zoomed image may be moved along one axis before its edge comes away
109
+ * from the screen's. Zero while the scaled image is smaller than the screen,
110
+ * which keeps it centred on that axis.
111
+ */
112
+ export function panBound(fitted: number, scale: number, viewport: number): number {
113
+ 'worklet';
114
+ return Math.max(0, (fitted * scale - viewport) / 2);
115
+ }
116
+
117
+ /**
118
+ * The translation that keeps a point under the fingers while the scale changes.
119
+ *
120
+ * `offset` is where that point sat relative to the image's centre when the
121
+ * pinch began, at `fromScale`; `focal` is the fingers' position now, relative
122
+ * to the screen's centre. The result is measured from the screen's centre too.
123
+ */
124
+ export function focalTranslation(
125
+ focal: number,
126
+ offset: number,
127
+ fromScale: number,
128
+ toScale: number
129
+ ): number {
130
+ 'worklet';
131
+ if (fromScale === 0) return focal;
132
+ return focal - offset * (toScale / fromScale);
133
+ }
134
+
135
+ /**
136
+ * The page a released pager settles on. Where it would have coasted to decides
137
+ * it rather than where it was let go, so a short flick still turns the page —
138
+ * but never by more than one, which is what a flick means.
139
+ */
140
+ export function snapPage(
141
+ offset: number,
142
+ velocity: number,
143
+ current: number,
144
+ count: number,
145
+ pageWidth: number
146
+ ): number {
147
+ 'worklet';
148
+ if (count <= 1 || pageWidth <= 0) return 0;
149
+ const projected = -(offset + velocity * 0.25) / pageWidth;
150
+ const target = Math.round(projected);
151
+ return clamp(clamp(target, current - 1, current + 1), 0, count - 1);
152
+ }
153
+
154
+ /** How far a drag has to travel, counting where it was flung, to close the viewer. */
155
+ export const DISMISS_DISTANCE = 110;
156
+
157
+ /**
158
+ * Whether a released drag closes the viewer.
159
+ *
160
+ * Measured on where the image was heading rather than where it was dropped, so
161
+ * a quick flick closes it from a short distance and a slow drag that is let go
162
+ * of carefully does not. A throw back towards the centre cancels.
163
+ */
164
+ export function shouldDismiss(translation: number, velocity: number): boolean {
165
+ 'worklet';
166
+ const projected = translation + velocity * 0.2;
167
+ if (Math.abs(projected) <= DISMISS_DISTANCE) return false;
168
+ return translation === 0 || Math.sign(projected) === Math.sign(translation);
169
+ }
170
+
171
+ /**
172
+ * How much of the backdrop is left while the image is dragged away from the
173
+ * centre. It is mostly gone by the time the drag would close the viewer, so the
174
+ * page coming back into focus is the warning that letting go will close it.
175
+ */
176
+ export function dragFade(distance: number, viewport: number): number {
177
+ 'worklet';
178
+ if (viewport <= 0) return 1;
179
+ return 1 - clamp(Math.abs(distance) / (viewport * 0.4), 0, 1) * 0.85;
180
+ }
181
+
182
+ /** How small the image gets while it is dragged. Never below 0.8 of its size. */
183
+ export function dragScale(distance: number, viewport: number): number {
184
+ 'worklet';
185
+ if (viewport <= 0) return 1;
186
+ return 1 - clamp(Math.abs(distance) / viewport, 0, 1) * 0.2;
187
+ }
188
+
189
+ /** Whether a point lands on a rect that has been scaled about its centre and moved. */
190
+ export function hitsRect(
191
+ px: number,
192
+ py: number,
193
+ rect: Rect,
194
+ scale: number,
195
+ tx: number,
196
+ ty: number
197
+ ): boolean {
198
+ 'worklet';
199
+ const cx = rect.x + rect.width / 2 + tx;
200
+ const cy = rect.y + rect.height / 2 + ty;
201
+ return (
202
+ Math.abs(px - cx) <= (rect.width * scale) / 2 &&
203
+ Math.abs(py - cy) <= (rect.height * scale) / 2
204
+ );
205
+ }