panelui-native 0.12.0 → 0.14.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 (93) hide show
  1. package/README.md +39 -23
  2. package/lib/module/components/button/index.js +12 -9
  3. package/lib/module/components/button/index.js.map +1 -1
  4. package/lib/module/components/chip/index.js +313 -0
  5. package/lib/module/components/chip/index.js.map +1 -0
  6. package/lib/module/components/frame/index.js +41 -39
  7. package/lib/module/components/frame/index.js.map +1 -1
  8. package/lib/module/components/heatmap-chart/index.js +772 -0
  9. package/lib/module/components/heatmap-chart/index.js.map +1 -0
  10. package/lib/module/components/input/index.js +4 -0
  11. package/lib/module/components/input/index.js.map +1 -1
  12. package/lib/module/components/scroll-canvas/index.js +175 -0
  13. package/lib/module/components/scroll-canvas/index.js.map +1 -0
  14. package/lib/module/components/scroll-text/index.js +213 -0
  15. package/lib/module/components/scroll-text/index.js.map +1 -0
  16. package/lib/module/components/select/index.js +20 -24
  17. package/lib/module/components/select/index.js.map +1 -1
  18. package/lib/module/components/slider/index.js +2 -5
  19. package/lib/module/components/slider/index.js.map +1 -1
  20. package/lib/module/components/switch/index.js +15 -17
  21. package/lib/module/components/switch/index.js.map +1 -1
  22. package/lib/module/components/thinking-orb/index.js +741 -0
  23. package/lib/module/components/thinking-orb/index.js.map +1 -0
  24. package/lib/module/components/toggle-button/index.js +12 -3
  25. package/lib/module/components/toggle-button/index.js.map +1 -1
  26. package/lib/module/hooks/index.js +1 -0
  27. package/lib/module/hooks/index.js.map +1 -1
  28. package/lib/module/hooks/use-keyboard-avoidance.js +99 -59
  29. package/lib/module/hooks/use-keyboard-avoidance.js.map +1 -1
  30. package/lib/module/hooks/use-reveal-progress.js +75 -0
  31. package/lib/module/hooks/use-reveal-progress.js.map +1 -0
  32. package/lib/module/index.js +6 -0
  33. package/lib/module/index.js.map +1 -1
  34. package/lib/module/native/index.js.map +1 -1
  35. package/lib/module/primitives/keyboard-avoider.js +21 -2
  36. package/lib/module/primitives/keyboard-avoider.js.map +1 -1
  37. package/lib/module/primitives/scroll-progress.js +114 -0
  38. package/lib/module/primitives/scroll-progress.js.map +1 -0
  39. package/lib/typescript/src/components/button/index.d.ts +3 -4
  40. package/lib/typescript/src/components/button/index.d.ts.map +1 -1
  41. package/lib/typescript/src/components/chip/index.d.ts +304 -0
  42. package/lib/typescript/src/components/chip/index.d.ts.map +1 -0
  43. package/lib/typescript/src/components/frame/index.d.ts +15 -13
  44. package/lib/typescript/src/components/frame/index.d.ts.map +1 -1
  45. package/lib/typescript/src/components/heatmap-chart/index.d.ts +260 -0
  46. package/lib/typescript/src/components/heatmap-chart/index.d.ts.map +1 -0
  47. package/lib/typescript/src/components/input/index.d.ts +19 -4
  48. package/lib/typescript/src/components/input/index.d.ts.map +1 -1
  49. package/lib/typescript/src/components/scroll-canvas/index.d.ts +66 -0
  50. package/lib/typescript/src/components/scroll-canvas/index.d.ts.map +1 -0
  51. package/lib/typescript/src/components/scroll-text/index.d.ts +46 -0
  52. package/lib/typescript/src/components/scroll-text/index.d.ts.map +1 -0
  53. package/lib/typescript/src/components/select/index.d.ts.map +1 -1
  54. package/lib/typescript/src/components/slider/index.d.ts.map +1 -1
  55. package/lib/typescript/src/components/switch/index.d.ts.map +1 -1
  56. package/lib/typescript/src/components/thinking-orb/index.d.ts +28 -0
  57. package/lib/typescript/src/components/thinking-orb/index.d.ts.map +1 -0
  58. package/lib/typescript/src/components/toggle-button/index.d.ts +12 -0
  59. package/lib/typescript/src/components/toggle-button/index.d.ts.map +1 -1
  60. package/lib/typescript/src/hooks/index.d.ts +2 -1
  61. package/lib/typescript/src/hooks/index.d.ts.map +1 -1
  62. package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts +16 -3
  63. package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts.map +1 -1
  64. package/lib/typescript/src/hooks/use-reveal-progress.d.ts +56 -0
  65. package/lib/typescript/src/hooks/use-reveal-progress.d.ts.map +1 -0
  66. package/lib/typescript/src/index.d.ts +6 -0
  67. package/lib/typescript/src/index.d.ts.map +1 -1
  68. package/lib/typescript/src/native/index.d.ts +15 -7
  69. package/lib/typescript/src/native/index.d.ts.map +1 -1
  70. package/lib/typescript/src/primitives/keyboard-avoider.d.ts +30 -3
  71. package/lib/typescript/src/primitives/keyboard-avoider.d.ts.map +1 -1
  72. package/lib/typescript/src/primitives/scroll-progress.d.ts +61 -0
  73. package/lib/typescript/src/primitives/scroll-progress.d.ts.map +1 -0
  74. package/package.json +1 -1
  75. package/src/components/button/index.tsx +13 -11
  76. package/src/components/chip/index.tsx +333 -0
  77. package/src/components/frame/index.tsx +39 -50
  78. package/src/components/heatmap-chart/index.tsx +1024 -0
  79. package/src/components/input/index.tsx +23 -4
  80. package/src/components/scroll-canvas/index.tsx +220 -0
  81. package/src/components/scroll-text/index.tsx +277 -0
  82. package/src/components/select/index.tsx +4 -9
  83. package/src/components/slider/index.tsx +4 -7
  84. package/src/components/switch/index.tsx +5 -8
  85. package/src/components/thinking-orb/index.tsx +792 -0
  86. package/src/components/toggle-button/index.tsx +24 -2
  87. package/src/hooks/index.ts +6 -0
  88. package/src/hooks/use-keyboard-avoidance.ts +111 -65
  89. package/src/hooks/use-reveal-progress.ts +106 -0
  90. package/src/index.ts +46 -0
  91. package/src/native/index.ts +15 -7
  92. package/src/primitives/keyboard-avoider.tsx +41 -4
  93. package/src/primitives/scroll-progress.tsx +167 -0
@@ -0,0 +1,167 @@
1
+ /**
2
+ * ScrollProgress — publishes a scroll container's position so children can
3
+ * animate against it.
4
+ *
5
+ * Scroll-driven effects all need the same two numbers: where the scroller is,
6
+ * and how tall its viewport is. Every component that wanted them measuring for
7
+ * itself would mean one scroll listener per effect and one measurement pass per
8
+ * effect per frame, for two values that are the same for all of them.
9
+ *
10
+ * It wraps the scroll view you already have rather than replacing it — the
11
+ * child is cloned with an animated scroll handler composed onto it, the same
12
+ * way `ScrollFade` does — so a `FlatList`, a `SectionList` or your own
13
+ * scrollable all work, and nothing has to be rewritten to adopt it.
14
+ *
15
+ * ```tsx
16
+ * <ScrollProgress>
17
+ * <ScrollView>
18
+ * <ScrollText>…</ScrollText>
19
+ * </ScrollView>
20
+ * </ScrollProgress>
21
+ * ```
22
+ *
23
+ * Both values are shared values, so the whole chain from scroll event to
24
+ * animated style stays on the UI thread and nothing re-renders as you scroll.
25
+ */
26
+ import {
27
+ Children,
28
+ createContext,
29
+ isValidElement,
30
+ useContext,
31
+ useMemo,
32
+ useRef,
33
+ type ComponentType,
34
+ type ReactElement,
35
+ type ReactNode,
36
+ } from 'react';
37
+ import { View, type LayoutChangeEvent, type ViewProps } from 'react-native';
38
+ import Animated, {
39
+ useAnimatedScrollHandler,
40
+ useComposedEventHandler,
41
+ useSharedValue,
42
+ type AnimatedScrollViewProps,
43
+ type SharedValue,
44
+ } from 'react-native-reanimated';
45
+
46
+ export interface ScrollProgressValue {
47
+ /** Distance scrolled, in pixels. */
48
+ offset: SharedValue<number>;
49
+ /** Height of the visible area. */
50
+ viewport: SharedValue<number>;
51
+ /** Total height of the content. */
52
+ content: SharedValue<number>;
53
+ /**
54
+ * Window-space top edge of the scroller. What turns an element's measured
55
+ * `pageY` into a position inside *this* viewport rather than the screen's —
56
+ * they differ by whatever sits above the scroller, and assuming they do not
57
+ * is why scroll effects drift under a header.
58
+ */
59
+ top: SharedValue<number>;
60
+ }
61
+
62
+ const ScrollProgressContext = createContext<ScrollProgressValue | null>(null);
63
+
64
+ /**
65
+ * The nearest enclosing scroll container's position, or `null` outside one.
66
+ *
67
+ * It returns null rather than throwing because every consumer of this also
68
+ * takes an explicit `progress` prop — a component that can be driven by hand
69
+ * should not insist on a provider it does not need.
70
+ */
71
+ export function useScrollProgress(): ScrollProgressValue | null {
72
+ return useContext(ScrollProgressContext);
73
+ }
74
+
75
+ interface ScrollableProps {
76
+ onScroll?: AnimatedScrollViewProps['onScroll'];
77
+ onLayout?: (event: LayoutChangeEvent) => void;
78
+ onContentSizeChange?: (width: number, height: number) => void;
79
+ scrollEventThrottle?: number;
80
+ }
81
+
82
+ export interface ScrollProgressProps extends ViewProps {
83
+ className?: string;
84
+ /** Exactly one scrollable — a ScrollView, FlatList, or anything like them. */
85
+ children?: ReactNode;
86
+ }
87
+
88
+ export function ScrollProgress({ className, children, ...props }: ScrollProgressProps) {
89
+ const offset = useSharedValue(0);
90
+ const viewport = useSharedValue(0);
91
+ const content = useSharedValue(0);
92
+ const top = useSharedValue(0);
93
+ const hostRef = useRef<View>(null);
94
+
95
+ const child = Children.only(children) as ReactElement<ScrollableProps>;
96
+
97
+ // Reanimated can only drive a scroll handler on an animated component, and
98
+ // what was passed in is not necessarily `Animated.ScrollView`. Keyed on the
99
+ // element *type*, not the element: rebuilding the wrapper would remount the
100
+ // list and lose its scroll position.
101
+ const childType = isValidElement(child)
102
+ ? (child.type as ComponentType<ScrollableProps>)
103
+ : null;
104
+ const AnimatedScrollable = useMemo(
105
+ () => (childType ? Animated.createAnimatedComponent(childType) : null),
106
+ [childType]
107
+ );
108
+
109
+ const scrollHandler = useAnimatedScrollHandler({
110
+ onScroll: (event) => {
111
+ offset.value = event.contentOffset.y;
112
+ viewport.value = event.layoutMeasurement.height;
113
+ content.value = event.contentSize.height;
114
+ },
115
+ });
116
+
117
+ // A consumer's own `onScroll` is composed rather than dropped — but since the
118
+ // child is now an animated component, it has to be an animated handler too.
119
+ const onScroll = useComposedEventHandler([
120
+ scrollHandler,
121
+ (child.props.onScroll as typeof scrollHandler | undefined) ?? null,
122
+ ]);
123
+
124
+ // Taken up front as well as on scroll, so anything already on screen animates
125
+ // from the first frame instead of waiting for the first scroll event.
126
+ const onLayout = (event: LayoutChangeEvent) => {
127
+ viewport.value = event.nativeEvent.layout.height;
128
+ // A frame later than onLayout on both platforms, because measureInWindow
129
+ // is only meaningful once the view is attached and positioned.
130
+ requestAnimationFrame(() => {
131
+ hostRef.current?.measureInWindow((_x, y) => {
132
+ if (y >= 0) top.value = y;
133
+ });
134
+ });
135
+ child.props.onLayout?.(event);
136
+ };
137
+
138
+ const onContentSizeChange = (width: number, height: number) => {
139
+ content.value = height;
140
+ child.props.onContentSizeChange?.(width, height);
141
+ };
142
+
143
+ const value = useMemo<ScrollProgressValue>(
144
+ () => ({ offset, viewport, content, top }),
145
+ [offset, viewport, content, top]
146
+ );
147
+
148
+ return (
149
+ <ScrollProgressContext.Provider value={value}>
150
+ <View {...props} ref={hostRef} className={className}>
151
+ {AnimatedScrollable && isValidElement(child) ? (
152
+ <AnimatedScrollable
153
+ {...child.props}
154
+ onScroll={onScroll}
155
+ onLayout={onLayout}
156
+ onContentSizeChange={onContentSizeChange}
157
+ scrollEventThrottle={child.props.scrollEventThrottle ?? 16}
158
+ />
159
+ ) : (
160
+ child
161
+ )}
162
+ </View>
163
+ </ScrollProgressContext.Provider>
164
+ );
165
+ }
166
+
167
+ ScrollProgress.displayName = 'ScrollProgress';