panelui-native 0.76.0 → 0.78.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 (125) hide show
  1. package/lib/module/components/ai-input/index.js +23 -7
  2. package/lib/module/components/ai-input/index.js.map +1 -1
  3. package/lib/module/components/area-chart/index.js +32 -25
  4. package/lib/module/components/area-chart/index.js.map +1 -1
  5. package/lib/module/components/bottom-sheet/index.js +98 -15
  6. package/lib/module/components/bottom-sheet/index.js.map +1 -1
  7. package/lib/module/components/button/index.js +7 -1
  8. package/lib/module/components/button/index.js.map +1 -1
  9. package/lib/module/components/funnel-chart/index.js +15 -2
  10. package/lib/module/components/funnel-chart/index.js.map +1 -1
  11. package/lib/module/components/heatmap-chart/index.js +19 -27
  12. package/lib/module/components/heatmap-chart/index.js.map +1 -1
  13. package/lib/module/components/hex-chart/index.js +2 -0
  14. package/lib/module/components/hex-chart/index.js.map +1 -1
  15. package/lib/module/components/line-chart/index.js +38 -31
  16. package/lib/module/components/line-chart/index.js.map +1 -1
  17. package/lib/module/components/marquee/index.js +91 -5
  18. package/lib/module/components/marquee/index.js.map +1 -1
  19. package/lib/module/components/pie-chart/index.js +15 -2
  20. package/lib/module/components/pie-chart/index.js.map +1 -1
  21. package/lib/module/components/plot/index.js +42 -44
  22. package/lib/module/components/plot/index.js.map +1 -1
  23. package/lib/module/components/progress-button/index.js +390 -0
  24. package/lib/module/components/progress-button/index.js.map +1 -0
  25. package/lib/module/components/progress-button/progress-button-hold.js +57 -0
  26. package/lib/module/components/progress-button/progress-button-hold.js.map +1 -0
  27. package/lib/module/components/scatter-chart/index.js +6 -25
  28. package/lib/module/components/scatter-chart/index.js.map +1 -1
  29. package/lib/module/components/section-rail/index.js +40 -17
  30. package/lib/module/components/section-rail/index.js.map +1 -1
  31. package/lib/module/components/select/index.js +1 -0
  32. package/lib/module/components/select/index.js.map +1 -1
  33. package/lib/module/components/slider/index.js +1 -0
  34. package/lib/module/components/slider/index.js.map +1 -1
  35. package/lib/module/components/split-view/index.js +54 -10
  36. package/lib/module/components/split-view/index.js.map +1 -1
  37. package/lib/module/components/switch/index.js +1 -0
  38. package/lib/module/components/switch/index.js.map +1 -1
  39. package/lib/module/components/timeline/index.js +145 -14
  40. package/lib/module/components/timeline/index.js.map +1 -1
  41. package/lib/module/components/toast/index.js +45 -11
  42. package/lib/module/components/toast/index.js.map +1 -1
  43. package/lib/module/components/treemap-chart/index.js +63 -6
  44. package/lib/module/components/treemap-chart/index.js.map +1 -1
  45. package/lib/module/components/waterfall-chart/index.js +20 -4
  46. package/lib/module/components/waterfall-chart/index.js.map +1 -1
  47. package/lib/module/hooks/index.js +1 -0
  48. package/lib/module/hooks/index.js.map +1 -1
  49. package/lib/module/hooks/use-scroll-sections.js +44 -2
  50. package/lib/module/hooks/use-scroll-sections.js.map +1 -1
  51. package/lib/module/hooks/use-skeleton-handoff.js +58 -0
  52. package/lib/module/hooks/use-skeleton-handoff.js.map +1 -0
  53. package/lib/module/index.js +1 -0
  54. package/lib/module/index.js.map +1 -1
  55. package/lib/module/native/index.js.map +1 -1
  56. package/lib/typescript/src/components/ai-input/index.d.ts +24 -5
  57. package/lib/typescript/src/components/ai-input/index.d.ts.map +1 -1
  58. package/lib/typescript/src/components/area-chart/index.d.ts +1 -1
  59. package/lib/typescript/src/components/area-chart/index.d.ts.map +1 -1
  60. package/lib/typescript/src/components/bottom-sheet/index.d.ts.map +1 -1
  61. package/lib/typescript/src/components/button/index.d.ts +15 -0
  62. package/lib/typescript/src/components/button/index.d.ts.map +1 -1
  63. package/lib/typescript/src/components/funnel-chart/index.d.ts.map +1 -1
  64. package/lib/typescript/src/components/heatmap-chart/index.d.ts.map +1 -1
  65. package/lib/typescript/src/components/hex-chart/index.d.ts.map +1 -1
  66. package/lib/typescript/src/components/line-chart/index.d.ts +1 -1
  67. package/lib/typescript/src/components/line-chart/index.d.ts.map +1 -1
  68. package/lib/typescript/src/components/marquee/index.d.ts +55 -2
  69. package/lib/typescript/src/components/marquee/index.d.ts.map +1 -1
  70. package/lib/typescript/src/components/pie-chart/index.d.ts.map +1 -1
  71. package/lib/typescript/src/components/plot/index.d.ts +1 -3
  72. package/lib/typescript/src/components/plot/index.d.ts.map +1 -1
  73. package/lib/typescript/src/components/progress-button/index.d.ts +295 -0
  74. package/lib/typescript/src/components/progress-button/index.d.ts.map +1 -0
  75. package/lib/typescript/src/components/progress-button/progress-button-hold.d.ts +40 -0
  76. package/lib/typescript/src/components/progress-button/progress-button-hold.d.ts.map +1 -0
  77. package/lib/typescript/src/components/scatter-chart/index.d.ts +1 -1
  78. package/lib/typescript/src/components/scatter-chart/index.d.ts.map +1 -1
  79. package/lib/typescript/src/components/section-rail/index.d.ts.map +1 -1
  80. package/lib/typescript/src/components/split-view/index.d.ts +10 -1
  81. package/lib/typescript/src/components/split-view/index.d.ts.map +1 -1
  82. package/lib/typescript/src/components/timeline/index.d.ts +7 -0
  83. package/lib/typescript/src/components/timeline/index.d.ts.map +1 -1
  84. package/lib/typescript/src/components/toast/index.d.ts.map +1 -1
  85. package/lib/typescript/src/components/treemap-chart/index.d.ts.map +1 -1
  86. package/lib/typescript/src/components/waterfall-chart/index.d.ts.map +1 -1
  87. package/lib/typescript/src/hooks/index.d.ts +1 -0
  88. package/lib/typescript/src/hooks/index.d.ts.map +1 -1
  89. package/lib/typescript/src/hooks/use-scroll-sections.d.ts +1 -0
  90. package/lib/typescript/src/hooks/use-scroll-sections.d.ts.map +1 -1
  91. package/lib/typescript/src/hooks/use-skeleton-handoff.d.ts +11 -0
  92. package/lib/typescript/src/hooks/use-skeleton-handoff.d.ts.map +1 -0
  93. package/lib/typescript/src/index.d.ts +3 -2
  94. package/lib/typescript/src/index.d.ts.map +1 -1
  95. package/lib/typescript/src/native/index.d.ts +17 -0
  96. package/lib/typescript/src/native/index.d.ts.map +1 -1
  97. package/package.json +1 -1
  98. package/src/components/ai-input/index.tsx +46 -12
  99. package/src/components/area-chart/index.tsx +49 -37
  100. package/src/components/bottom-sheet/index.tsx +110 -12
  101. package/src/components/button/index.tsx +20 -1
  102. package/src/components/funnel-chart/index.tsx +10 -2
  103. package/src/components/heatmap-chart/index.tsx +27 -22
  104. package/src/components/hex-chart/index.tsx +22 -6
  105. package/src/components/line-chart/index.tsx +57 -43
  106. package/src/components/marquee/index.tsx +129 -6
  107. package/src/components/pie-chart/index.tsx +10 -2
  108. package/src/components/plot/index.tsx +66 -50
  109. package/src/components/progress-button/index.tsx +465 -0
  110. package/src/components/progress-button/progress-button-hold.ts +57 -0
  111. package/src/components/scatter-chart/index.tsx +4 -25
  112. package/src/components/section-rail/index.tsx +39 -19
  113. package/src/components/select/index.tsx +1 -1
  114. package/src/components/slider/index.tsx +1 -1
  115. package/src/components/split-view/index.tsx +53 -8
  116. package/src/components/switch/index.tsx +1 -1
  117. package/src/components/timeline/index.tsx +143 -17
  118. package/src/components/toast/index.tsx +60 -11
  119. package/src/components/treemap-chart/index.tsx +65 -8
  120. package/src/components/waterfall-chart/index.tsx +14 -4
  121. package/src/hooks/index.ts +5 -0
  122. package/src/hooks/use-scroll-sections.ts +52 -3
  123. package/src/hooks/use-skeleton-handoff.ts +69 -0
  124. package/src/index.ts +10 -0
  125. package/src/native/index.ts +17 -0
@@ -89,7 +89,6 @@ import Animated, {
89
89
  } from 'react-native-reanimated';
90
90
  import Svg, {
91
91
  Circle,
92
- ClipPath,
93
92
  Defs,
94
93
  G,
95
94
  Line as SvgLine,
@@ -142,7 +141,6 @@ export {
142
141
  export type { Plot as PlotBox, ChartPoint } from '../../utils/chart';
143
142
 
144
143
  const AnimatedPath = Animated.createAnimatedComponent(Path);
145
- const AnimatedRect = Animated.createAnimatedComponent(Rect);
146
144
  const AnimatedCircle = Animated.createAnimatedComponent(Circle);
147
145
 
148
146
  /** Room left around the plot for the axis labels and the markers' rings. */
@@ -168,7 +166,7 @@ const LABEL_WIDTH = 120;
168
166
  * stays a flat list of children instead of three nested slots whose order the
169
167
  * caller has to remember.
170
168
  */
171
- type Layer = 'svg' | 'overlay' | 'header';
169
+ type Layer = 'svg' | 'series' | 'overlay' | 'header';
172
170
 
173
171
  export type PlotStatus = 'loading' | 'ready';
174
172
  export type PlotCurve = 'monotone' | 'linear';
@@ -229,7 +227,6 @@ export interface PlotGeometry {
229
227
  activeIndexJS: number;
230
228
  setActiveIndexJS: (index: number) => void;
231
229
  /** The clip every mark shares, so they are revealed as one drawing. */
232
- clipId: string;
233
230
  }
234
231
 
235
232
  const PlotContext = createContext<PlotGeometry | null>(null);
@@ -355,7 +352,6 @@ const PlotRoot = forwardRef<PlotHandle, PlotProps>(function PlotRoot(
355
352
  const [size, setSize] = useState({ width: 0, height: 0 });
356
353
  const [registrations, setRegistrations] = useState<PlotSeriesRegistration[]>([]);
357
354
  const [activeIndexJS, setActiveIndexJS] = useState(-1);
358
- const clipId = `panelui-plot-${useId().replace(/[^a-zA-Z0-9]/g, '')}`;
359
355
 
360
356
  const reveal = useSharedValue(0);
361
357
  const domainMin = useSharedValue(0);
@@ -584,7 +580,6 @@ const PlotRoot = forwardRef<PlotHandle, PlotProps>(function PlotRoot(
584
580
  activeIndex,
585
581
  activeIndexJS,
586
582
  setActiveIndexJS: handleActiveIndex,
587
- clipId,
588
583
  }),
589
584
  // `plot` is rebuilt every render from `size`, so it is compared by value.
590
585
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -608,13 +603,12 @@ const PlotRoot = forwardRef<PlotHandle, PlotProps>(function PlotRoot(
608
603
  activeIndex,
609
604
  activeIndexJS,
610
605
  handleActiveIndex,
611
- clipId,
612
606
  ]
613
607
  );
614
608
 
615
- const clipProps = useAnimatedProps(() => ({ width: plot.width * reveal.value }));
609
+ const revealStyle = useAnimatedStyle(() => ({ width: plot.width * reveal.value }));
616
610
 
617
- const { svg, overlay, header } = partition(children);
611
+ const { svg, series: seriesLayer, overlay, header } = partition(children);
618
612
 
619
613
  /*
620
614
  * Two views, because the header is not part of the plot. `aspectRatio` and
@@ -649,32 +643,45 @@ const PlotRoot = forwardRef<PlotHandle, PlotProps>(function PlotRoot(
649
643
  {plot.width > 0 ? (
650
644
  <>
651
645
  <Svg width="100%" height="100%" style={StyleSheet.absoluteFill}>
652
- <Defs>
653
- {/*
654
- * One clip for every mark. Sharing it is what makes the reveal
655
- * read as the chart arriving, rather than as four separate
656
- * things animating in at once — which is the thing a composed
657
- * chart is most at risk of looking like.
658
- *
659
- * `width` is set statically as well as animated, and it has
660
- * to be. Animated props on an element inside `Defs` do not
661
- * reach the native clip on every platform, and with the width
662
- * coming only from the animation there is no width at all
663
- * when they do not — an empty clip, and marks that never
664
- * appear while the axes draw normally.
665
- */}
666
- <ClipPath id={clipId}>
667
- <AnimatedRect
668
- x={plot.left}
669
- y={0}
670
- width={plot.width}
671
- height={size.height}
672
- animatedProps={clipProps}
673
- />
674
- </ClipPath>
675
- </Defs>
676
646
  {svg}
677
647
  </Svg>
648
+ {/*
649
+ * One reveal for every mark, and it is a view that grows rather
650
+ * than an SVG clip path. Sharing it is what makes the reveal read
651
+ * as the chart arriving, rather than as four separate things
652
+ * animating in at once — which is the thing a composed chart is
653
+ * most at risk of looking like.
654
+ *
655
+ * It used to be an animated `<Rect>` inside `<Defs>`, and on
656
+ * Android those animated props never reach the native clip — the
657
+ * rect keeps whatever width was declared on it, so the marks drew
658
+ * complete and the reveal simply did not play. A view with
659
+ * `overflow: 'hidden'` is clipped by the platform itself, which
660
+ * both platforms agree on.
661
+ *
662
+ * Animating `width` is normally a layout pass per frame. Here the
663
+ * view is absolutely positioned and its only child is an `<Svg>`
664
+ * with an explicit width and height, so the work is one node and
665
+ * nothing around it moves.
666
+ *
667
+ * The inner `<Svg>` is pulled back by `plot.left` so the marks
668
+ * keep the same coordinate space as the grid underneath them.
669
+ */}
670
+ <Animated.View
671
+ pointerEvents="none"
672
+ style={[
673
+ { position: 'absolute', top: 0, bottom: 0, left: plot.left, overflow: 'hidden' },
674
+ revealStyle,
675
+ ]}
676
+ >
677
+ <Svg
678
+ width={size.width}
679
+ height={size.height}
680
+ style={{ position: 'absolute', top: 0, left: -plot.left }}
681
+ >
682
+ {seriesLayer}
683
+ </Svg>
684
+ </Animated.View>
678
685
  {overlay}
679
686
  </>
680
687
  ) : null}
@@ -688,20 +695,29 @@ PlotRoot.displayName = 'Plot';
688
695
  /** Sorts the children into the SVG tree, the view layer over it, and the header. */
689
696
  function partition(children: ReactNode) {
690
697
  const svg: ReactNode[] = [];
698
+ const series: ReactNode[] = [];
691
699
  const overlay: ReactNode[] = [];
692
700
  const header: ReactNode[] = [];
693
701
 
694
702
  Children.forEach(children, (child, index) => {
695
703
  if (!isValidElement(child)) return;
696
704
  const layer = (child.type as { layer?: Layer }).layer ?? 'svg';
697
- (layer === 'header' ? header : layer === 'overlay' ? overlay : svg).push(
705
+ const bucket =
706
+ layer === 'header'
707
+ ? header
708
+ : layer === 'overlay'
709
+ ? overlay
710
+ : layer === 'series'
711
+ ? series
712
+ : svg;
713
+ bucket.push(
698
714
  // Children of a `Children.forEach` need keys of their own once they are
699
715
  // put into a new array.
700
716
  <ChildSlot key={index}>{child}</ChildSlot>
701
717
  );
702
718
  });
703
719
 
704
- return { svg, overlay, header };
720
+ return { svg, series, overlay, header };
705
721
  }
706
722
 
707
723
  /** Identity wrapper, purely so the partitioned arrays can carry keys. */
@@ -801,7 +817,7 @@ function PlotLine({
801
817
  curve = 'monotone',
802
818
  dashArray,
803
819
  }: PlotLineProps) {
804
- const { data, plot, xScale, domainMin, domainMax, status, clipId } =
820
+ const { data, plot, xScale, domainMin, domainMax, status } =
805
821
  useChart('Plot.Line');
806
822
  const stroke = useMark(dataKey, color, colorIndex);
807
823
 
@@ -830,7 +846,7 @@ function PlotLine({
830
846
  if (status === 'loading') return null;
831
847
 
832
848
  return (
833
- <G clipPath={`url(#${clipId})`}>
849
+ <G>
834
850
  <AnimatedPath
835
851
  animatedProps={animatedProps}
836
852
  fill="none"
@@ -844,7 +860,7 @@ function PlotLine({
844
860
  );
845
861
  }
846
862
  PlotLine.displayName = 'Plot.Line';
847
- PlotLine.layer = 'svg' as Layer;
863
+ PlotLine.layer = 'series' as Layer;
848
864
 
849
865
  export interface PlotAreaProps extends PlotSeriesProps {
850
866
  opacity?: number;
@@ -864,7 +880,7 @@ function PlotArea({
864
880
  opacity = 0.18,
865
881
  curve = 'monotone',
866
882
  }: PlotAreaProps) {
867
- const { data, plot, xScale, domainMin, domainMax, status, clipId } =
883
+ const { data, plot, xScale, domainMin, domainMax, status } =
868
884
  useChart('Plot.Area');
869
885
  const fill = useMark(dataKey, color, colorIndex);
870
886
  const values = useMemo(() => columnValues(data, dataKey), [data, dataKey]);
@@ -882,13 +898,13 @@ function PlotArea({
882
898
  if (status === 'loading') return null;
883
899
 
884
900
  return (
885
- <G clipPath={`url(#${clipId})`}>
901
+ <G>
886
902
  <AnimatedPath animatedProps={animatedProps} fill={fill} fillOpacity={opacity} />
887
903
  </G>
888
904
  );
889
905
  }
890
906
  PlotArea.displayName = 'Plot.Area';
891
- PlotArea.layer = 'svg' as Layer;
907
+ PlotArea.layer = 'series' as Layer;
892
908
 
893
909
  export interface PlotBarsProps extends PlotSeriesProps {
894
910
  /** Fraction of each slice left empty, `0` to `1`. */
@@ -928,7 +944,7 @@ function PlotBars({
928
944
  opacity = 1,
929
945
  baseline = 0,
930
946
  }: PlotBarsProps) {
931
- const { data, plot, domainMin, domainMax, status, clipId } = useChart('Plot.Bars');
947
+ const { data, plot, domainMin, domainMax, status } = useChart('Plot.Bars');
932
948
  const fill = useMark(dataKey, color, colorIndex);
933
949
  const values = useMemo(() => columnValues(data, dataKey), [data, dataKey]);
934
950
 
@@ -972,13 +988,13 @@ function PlotBars({
972
988
  if (status === 'loading') return null;
973
989
 
974
990
  return (
975
- <G clipPath={`url(#${clipId})`}>
991
+ <G>
976
992
  <AnimatedPath animatedProps={animatedProps} fill={fill} fillOpacity={opacity} />
977
993
  </G>
978
994
  );
979
995
  }
980
996
  PlotBars.displayName = 'Plot.Bars';
981
- PlotBars.layer = 'svg' as Layer;
997
+ PlotBars.layer = 'series' as Layer;
982
998
  // Read by the root before it resolves the scale: a mark with width cannot sit
983
999
  // on a point scale without half of the first and last one leaving the plot.
984
1000
  PlotBars.mark = 'band' as const;
@@ -998,7 +1014,7 @@ function PlotDots({
998
1014
  size = 3.5,
999
1015
  ringWidth = 2,
1000
1016
  }: PlotDotsProps) {
1001
- const { data, plot, xScale, domainMin, domainMax, status, clipId } =
1017
+ const { data, plot, xScale, domainMin, domainMax, status } =
1002
1018
  useChart('Plot.Dots');
1003
1019
  const fill = useMark(dataKey, color, colorIndex);
1004
1020
  const ringToken = useCSSVariable('--color-background');
@@ -1007,7 +1023,7 @@ function PlotDots({
1007
1023
  const banded = xScale === 'band';
1008
1024
 
1009
1025
  return (
1010
- <G clipPath={`url(#${clipId})`}>
1026
+ <G>
1011
1027
  {status === 'loading'
1012
1028
  ? null
1013
1029
  : values.map((value, index) =>
@@ -1034,7 +1050,7 @@ function PlotDots({
1034
1050
  );
1035
1051
  }
1036
1052
  PlotDots.displayName = 'Plot.Dots';
1037
- PlotDots.layer = 'svg' as Layer;
1053
+ PlotDots.layer = 'series' as Layer;
1038
1054
 
1039
1055
  /** One dot, whose y follows the domain tween. */
1040
1056
  function Dot({
@@ -1087,11 +1103,11 @@ export interface PlotLayerProps {
1087
1103
  * animates has to hold hooks of its own and a render prop is not a component.
1088
1104
  */
1089
1105
  function PlotLayer({ children }: PlotLayerProps) {
1090
- const { clipId } = useChart('Plot.Layer');
1091
- return <G clipPath={`url(#${clipId})`}>{children}</G>;
1106
+ useChart('Plot.Layer');
1107
+ return <G>{children}</G>;
1092
1108
  }
1093
1109
  PlotLayer.displayName = 'Plot.Layer';
1094
- PlotLayer.layer = 'svg' as Layer;
1110
+ PlotLayer.layer = 'series' as Layer;
1095
1111
 
1096
1112
  /* -------------------------------------------------------------------------- */
1097
1113
  /* Overlay layer */