panelui-native 0.86.1 → 0.88.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 (63) hide show
  1. package/README.md +4 -2
  2. package/lib/module/components/animated-badge/index.js +451 -0
  3. package/lib/module/components/animated-badge/index.js.map +1 -0
  4. package/lib/module/components/bottom-sheet/index.js +17 -6
  5. package/lib/module/components/bottom-sheet/index.js.map +1 -1
  6. package/lib/module/components/bubble-chart/index.js +1782 -0
  7. package/lib/module/components/bubble-chart/index.js.map +1 -0
  8. package/lib/module/components/feedback-dialog/index.js +474 -0
  9. package/lib/module/components/feedback-dialog/index.js.map +1 -0
  10. package/lib/module/components/pyramid-chart/index.js +1143 -0
  11. package/lib/module/components/pyramid-chart/index.js.map +1 -0
  12. package/lib/module/components/scroll-blur/index.js +363 -0
  13. package/lib/module/components/scroll-blur/index.js.map +1 -0
  14. package/lib/module/components/scroll-canvas/index.js +2 -0
  15. package/lib/module/components/scroll-canvas/index.js.map +1 -1
  16. package/lib/module/components/scroll-text/index.js +3 -0
  17. package/lib/module/components/scroll-text/index.js.map +1 -1
  18. package/lib/module/components/search-bar/index.js +753 -25
  19. package/lib/module/components/search-bar/index.js.map +1 -1
  20. package/lib/module/hooks/use-keyboard-avoidance.js +21 -1
  21. package/lib/module/hooks/use-keyboard-avoidance.js.map +1 -1
  22. package/lib/module/hooks/use-reveal-progress.js +21 -1
  23. package/lib/module/hooks/use-reveal-progress.js.map +1 -1
  24. package/lib/module/index.js +5 -0
  25. package/lib/module/index.js.map +1 -1
  26. package/lib/module/utils/chart.js +24 -0
  27. package/lib/module/utils/chart.js.map +1 -1
  28. package/lib/typescript/src/components/animated-badge/index.d.ts +224 -0
  29. package/lib/typescript/src/components/animated-badge/index.d.ts.map +1 -0
  30. package/lib/typescript/src/components/bottom-sheet/index.d.ts +1 -15
  31. package/lib/typescript/src/components/bottom-sheet/index.d.ts.map +1 -1
  32. package/lib/typescript/src/components/bubble-chart/index.d.ts +481 -0
  33. package/lib/typescript/src/components/bubble-chart/index.d.ts.map +1 -0
  34. package/lib/typescript/src/components/feedback-dialog/index.d.ts +156 -0
  35. package/lib/typescript/src/components/feedback-dialog/index.d.ts.map +1 -0
  36. package/lib/typescript/src/components/pyramid-chart/index.d.ts +328 -0
  37. package/lib/typescript/src/components/pyramid-chart/index.d.ts.map +1 -0
  38. package/lib/typescript/src/components/scroll-blur/index.d.ts +113 -0
  39. package/lib/typescript/src/components/scroll-blur/index.d.ts.map +1 -0
  40. package/lib/typescript/src/components/scroll-canvas/index.d.ts.map +1 -1
  41. package/lib/typescript/src/components/search-bar/index.d.ts +350 -6
  42. package/lib/typescript/src/components/search-bar/index.d.ts.map +1 -1
  43. package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts.map +1 -1
  44. package/lib/typescript/src/hooks/use-reveal-progress.d.ts +6 -27
  45. package/lib/typescript/src/hooks/use-reveal-progress.d.ts.map +1 -1
  46. package/lib/typescript/src/index.d.ts +6 -1
  47. package/lib/typescript/src/index.d.ts.map +1 -1
  48. package/lib/typescript/src/utils/chart.d.ts +14 -0
  49. package/lib/typescript/src/utils/chart.d.ts.map +1 -1
  50. package/package.json +1 -1
  51. package/src/components/animated-badge/index.tsx +513 -0
  52. package/src/components/bottom-sheet/index.tsx +23 -8
  53. package/src/components/bubble-chart/index.tsx +2145 -0
  54. package/src/components/feedback-dialog/index.tsx +557 -0
  55. package/src/components/pyramid-chart/index.tsx +1360 -0
  56. package/src/components/scroll-blur/index.tsx +466 -0
  57. package/src/components/scroll-canvas/index.tsx +2 -1
  58. package/src/components/scroll-text/index.tsx +3 -3
  59. package/src/components/search-bar/index.tsx +933 -45
  60. package/src/hooks/use-keyboard-avoidance.ts +24 -1
  61. package/src/hooks/use-reveal-progress.ts +30 -1
  62. package/src/index.ts +72 -1
  63. package/src/utils/chart.ts +27 -0
@@ -200,6 +200,27 @@ export function useKeyboardAvoidance({
200
200
  /** The translation currently applied, in pixels. Zero or negative. */
201
201
  const translation = useSharedValue(0);
202
202
 
203
+ /*
204
+ * Whether the element has been laid out at least once and is still mounted.
205
+ *
206
+ * `measure` warns when it is handed a view the layout engine has no metrics
207
+ * for — every frame between a mount and its first layout, and every frame
208
+ * after an unmount that the callback has not been stopped for yet. Neither
209
+ * is a fault, and neither can be answered by the `null` it returns, because
210
+ * the warning is printed before that null comes back. Running once a frame,
211
+ * one of these fills the log on its own.
212
+ *
213
+ * So the layout pass is what says the view can be measured, and the unmount
214
+ * is what takes it back.
215
+ */
216
+ const laidOut = useSharedValue(false);
217
+ useEffect(
218
+ () => () => {
219
+ laidOut.value = false;
220
+ },
221
+ [laidOut]
222
+ );
223
+
203
224
  // `active` is a plain prop and the worklets below cannot read props, so it is
204
225
  // mirrored — written in an effect, because touching a shared value during
205
226
  // render is a Reanimated strict-mode violation.
@@ -226,6 +247,7 @@ export function useKeyboardAvoidance({
226
247
  'worklet';
227
248
  const keyboardHeight = Math.abs(rawHeight.value);
228
249
  if (keyboardHeight === 0) return;
250
+ if (!laidOut.value) return;
229
251
 
230
252
  const frame = measure(ref);
231
253
  if (!frame || frame.height <= 0) return;
@@ -267,12 +289,13 @@ export function useKeyboardAvoidance({
267
289
 
268
290
  const onLayout = useCallback(
269
291
  (_event: LayoutChangeEvent) => {
292
+ laidOut.value = true;
270
293
  // A layout pass while the element is at rest means its slot moved for
271
294
  // some reason other than the keyboard. Anything left over from the last
272
295
  // lift belongs to the old slot.
273
296
  if (!tracking && translation.value !== 0) translation.value = 0;
274
297
  },
275
- [tracking, translation]
298
+ [laidOut, tracking, translation]
276
299
  );
277
300
 
278
301
  const animatedStyle = useAnimatedStyle(() => {
@@ -25,11 +25,13 @@
25
25
  * anything above it resizes; every frame is a measurement pass for a value that
26
26
  * only changes when the scroller moves.
27
27
  */
28
+ import { useCallback, useEffect } from 'react';
28
29
  import { useWindowDimensions, type View } from 'react-native';
29
30
  import {
30
31
  measure,
31
32
  useAnimatedRef,
32
33
  useDerivedValue,
34
+ useSharedValue,
33
35
  type AnimatedRef,
34
36
  type SharedValue,
35
37
  } from 'react-native-reanimated';
@@ -58,6 +60,12 @@ export interface UseRevealProgressOptions {
58
60
  export interface UseRevealProgressResult {
59
61
  /** Attach to the element whose travel drives the effect. */
60
62
  ref: AnimatedRef<View>;
63
+ /**
64
+ * Attach to the same element. It is what says the element can be measured —
65
+ * without it the effect still works, at the cost of a warning per frame for
66
+ * every element that is mounted but not yet laid out.
67
+ */
68
+ onLayout: () => void;
61
69
  /** `0` before, `1` after, scrubbed between. */
62
70
  progress: SharedValue<number>;
63
71
  }
@@ -72,6 +80,26 @@ export function useRevealProgress({
72
80
  const scroll = useScrollProgress();
73
81
  const { height: windowHeight } = useWindowDimensions();
74
82
 
83
+ /*
84
+ * Whether the element has been laid out at least once and is still mounted.
85
+ *
86
+ * `measure` warns when it is handed a view the layout engine has no metrics
87
+ * for, and the warning is printed before the `null` that would let a caller
88
+ * notice. A list of these runs its measurement on every scroll frame, so one
89
+ * element that has mounted but not laid out fills the log on its own — which
90
+ * is the case the warning itself names, and the one it is least useful for.
91
+ */
92
+ const laidOut = useSharedValue(false);
93
+ const onLayout = useCallback(() => {
94
+ laidOut.value = true;
95
+ }, [laidOut]);
96
+ useEffect(
97
+ () => () => {
98
+ laidOut.value = false;
99
+ },
100
+ [laidOut]
101
+ );
102
+
75
103
  const offset = scroll?.offset;
76
104
  const viewportValue = scroll?.viewport;
77
105
  const topValue = scroll?.top;
@@ -86,6 +114,7 @@ export function useRevealProgress({
86
114
  const viewport = viewportValue?.value || windowHeight;
87
115
  const viewportTop = topValue?.value ?? 0;
88
116
  if (viewport <= 0 || Number.isNaN(scrolled)) return 0;
117
+ if (!laidOut.value) return 0;
89
118
 
90
119
  const frame = measure(ref);
91
120
  if (!frame || frame.height <= 0) return 0;
@@ -102,5 +131,5 @@ export function useRevealProgress({
102
131
 
103
132
  // An external value is passed straight through, so a caller driving the
104
133
  // effect by hand never pays for the measurement.
105
- return { ref, progress: external ?? derived };
134
+ return { ref, onLayout, progress: external ?? derived };
106
135
  }
package/src/index.ts CHANGED
@@ -93,6 +93,12 @@ export {
93
93
  type AreaChartDatum,
94
94
  type AreaChartStatus,
95
95
  } from './components/area-chart';
96
+ export {
97
+ AnimatedBadge,
98
+ type AnimatedBadgeProps,
99
+ type AnimatedBadgeSize,
100
+ type AnimatedBadgeStatus,
101
+ } from './components/animated-badge';
96
102
  export { Badge, type BadgeProps } from './components/badge';
97
103
  export {
98
104
  BarChart,
@@ -180,6 +186,17 @@ export {
180
186
  type DialogProps,
181
187
  type DialogContentProps,
182
188
  } from './components/dialog';
189
+ export {
190
+ FeedbackDialog,
191
+ type FeedbackDialogProps,
192
+ type FeedbackDialogContentProps,
193
+ type FeedbackDialogPanelProps,
194
+ type FeedbackDialogCloseProps,
195
+ type FeedbackDialogFieldProps,
196
+ type FeedbackDialogFooterProps,
197
+ type FeedbackDialogActionProps,
198
+ type FeedbackDialogSubmitProps,
199
+ } from './components/feedback-dialog';
183
200
  export {
184
201
  Soundwave,
185
202
  type SoundwaveProps,
@@ -543,7 +560,17 @@ export {
543
560
  type NumberInputProps,
544
561
  } from './components/number-input';
545
562
  export { OtpInput, type OtpInputProps } from './components/otp-input';
546
- export { SearchBar, type SearchBarProps } from './components/search-bar';
563
+ export {
564
+ SearchBar,
565
+ type SearchBarProps,
566
+ type SearchBarActionProps,
567
+ type SearchBarItemProps,
568
+ type SearchBarSectionProps,
569
+ type SearchBarStatusProps,
570
+ type SearchBarTokenProps,
571
+ type SearchBarPanelMode,
572
+ type SearchBarPanelPlacement,
573
+ } from './components/search-bar';
547
574
  export {
548
575
  Panelside,
549
576
  usePanelside,
@@ -621,6 +648,45 @@ export {
621
648
  type LiveLineMomentumColors,
622
649
  type LiveLinePoint,
623
650
  } from './components/live-line-chart';
651
+ export {
652
+ BubbleChart,
653
+ useBubbleChart,
654
+ type BubbleChartProps,
655
+ type BubbleChartHandle,
656
+ type BubbleChartHeaderProps,
657
+ type BubbleChartGridProps,
658
+ type BubbleChartQuadrantsProps,
659
+ type BubbleChartTrendProps,
660
+ type BubbleChartBubblesProps,
661
+ type BubbleChartLabelsProps,
662
+ type BubbleChartSizeKeyProps,
663
+ type BubbleChartSkeletonProps,
664
+ type BubbleChartXAxisProps,
665
+ type BubbleChartYAxisProps,
666
+ type BubbleChartTooltipProps,
667
+ type BubbleChartLegendProps,
668
+ type BubbleChartDatum,
669
+ type BubbleChartPoint,
670
+ type BubbleChartStatus,
671
+ } from './components/bubble-chart';
672
+ export {
673
+ PyramidChart,
674
+ usePyramidChart,
675
+ type PyramidChartProps,
676
+ type PyramidChartHandle,
677
+ type PyramidChartHeaderProps,
678
+ type PyramidChartGridProps,
679
+ type PyramidChartBarProps,
680
+ type PyramidChartSkeletonProps,
681
+ type PyramidChartXAxisProps,
682
+ type PyramidChartYAxisProps,
683
+ type PyramidChartTooltipProps,
684
+ type PyramidChartLegendProps,
685
+ type PyramidChartDatum,
686
+ type PyramidChartStatus,
687
+ type PyramidChartSide,
688
+ type PyramidChartLabelPlacement,
689
+ } from './components/pyramid-chart';
624
690
  export {
625
691
  PolarAreaChart,
626
692
  usePolarAreaChart,
@@ -974,6 +1040,11 @@ export {
974
1040
  type ScatterChartPoint,
975
1041
  type ScatterChartStatus,
976
1042
  } from './components/scatter-chart';
1043
+ export {
1044
+ ScrollBlur,
1045
+ type ScrollBlurProps,
1046
+ type ScrollBlurTint,
1047
+ } from './components/scroll-blur';
977
1048
  export {
978
1049
  ScrollFade,
979
1050
  type ScrollFadeProps,
@@ -209,6 +209,33 @@ function mantissa(value: number): string {
209
209
  return trimZeros(value.toFixed(Math.abs(value) < 10 ? 1 : 0));
210
210
  }
211
211
 
212
+ /**
213
+ * A value's radius on a bubble scale, in points.
214
+ *
215
+ * The value maps to *area* and the radius is taken from it, so a bubble holding
216
+ * twice the value carries twice the ink. Mapping it to the radius instead
217
+ * quadruples the ink for a doubled value, and the reader believes the larger
218
+ * number by four times.
219
+ *
220
+ * `extent` is the smallest and largest value in the whole set, so one bubble's
221
+ * size means the same thing as another's. A degenerate extent — one row, or
222
+ * every value identical — puts everything at the top of the range rather than
223
+ * dividing by zero.
224
+ */
225
+ export function bubbleRadius(
226
+ value: number,
227
+ extent: readonly [number, number],
228
+ range: readonly [number, number]
229
+ ): number {
230
+ 'worklet';
231
+ const [min, max] = extent;
232
+ const [rMin, rMax] = range;
233
+ const ratio = max === min ? 1 : (value - min) / (max - min);
234
+ const clamped = ratio < 0 ? 0 : ratio > 1 ? 1 : ratio;
235
+ const area = rMin * rMin + clamped * (rMax * rMax - rMin * rMin);
236
+ return Math.sqrt(area);
237
+ }
238
+
212
239
  /** `12k` rather than `12400` — a readout has one line to say it in. */
213
240
  export function compactNumber(value: number): string {
214
241
  if (!Number.isFinite(value)) return String(value);