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.
- package/README.md +39 -23
- package/lib/module/components/button/index.js +12 -9
- package/lib/module/components/button/index.js.map +1 -1
- package/lib/module/components/chip/index.js +313 -0
- package/lib/module/components/chip/index.js.map +1 -0
- package/lib/module/components/frame/index.js +41 -39
- package/lib/module/components/frame/index.js.map +1 -1
- package/lib/module/components/heatmap-chart/index.js +772 -0
- package/lib/module/components/heatmap-chart/index.js.map +1 -0
- package/lib/module/components/input/index.js +4 -0
- package/lib/module/components/input/index.js.map +1 -1
- package/lib/module/components/scroll-canvas/index.js +175 -0
- package/lib/module/components/scroll-canvas/index.js.map +1 -0
- package/lib/module/components/scroll-text/index.js +213 -0
- package/lib/module/components/scroll-text/index.js.map +1 -0
- package/lib/module/components/select/index.js +20 -24
- package/lib/module/components/select/index.js.map +1 -1
- package/lib/module/components/slider/index.js +2 -5
- package/lib/module/components/slider/index.js.map +1 -1
- package/lib/module/components/switch/index.js +15 -17
- package/lib/module/components/switch/index.js.map +1 -1
- package/lib/module/components/thinking-orb/index.js +741 -0
- package/lib/module/components/thinking-orb/index.js.map +1 -0
- package/lib/module/components/toggle-button/index.js +12 -3
- package/lib/module/components/toggle-button/index.js.map +1 -1
- package/lib/module/hooks/index.js +1 -0
- package/lib/module/hooks/index.js.map +1 -1
- package/lib/module/hooks/use-keyboard-avoidance.js +99 -59
- package/lib/module/hooks/use-keyboard-avoidance.js.map +1 -1
- package/lib/module/hooks/use-reveal-progress.js +75 -0
- package/lib/module/hooks/use-reveal-progress.js.map +1 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/native/index.js.map +1 -1
- package/lib/module/primitives/keyboard-avoider.js +21 -2
- package/lib/module/primitives/keyboard-avoider.js.map +1 -1
- package/lib/module/primitives/scroll-progress.js +114 -0
- package/lib/module/primitives/scroll-progress.js.map +1 -0
- package/lib/typescript/src/components/button/index.d.ts +3 -4
- package/lib/typescript/src/components/button/index.d.ts.map +1 -1
- package/lib/typescript/src/components/chip/index.d.ts +304 -0
- package/lib/typescript/src/components/chip/index.d.ts.map +1 -0
- package/lib/typescript/src/components/frame/index.d.ts +15 -13
- package/lib/typescript/src/components/frame/index.d.ts.map +1 -1
- package/lib/typescript/src/components/heatmap-chart/index.d.ts +260 -0
- package/lib/typescript/src/components/heatmap-chart/index.d.ts.map +1 -0
- package/lib/typescript/src/components/input/index.d.ts +19 -4
- package/lib/typescript/src/components/input/index.d.ts.map +1 -1
- package/lib/typescript/src/components/scroll-canvas/index.d.ts +66 -0
- package/lib/typescript/src/components/scroll-canvas/index.d.ts.map +1 -0
- package/lib/typescript/src/components/scroll-text/index.d.ts +46 -0
- package/lib/typescript/src/components/scroll-text/index.d.ts.map +1 -0
- package/lib/typescript/src/components/select/index.d.ts.map +1 -1
- package/lib/typescript/src/components/slider/index.d.ts.map +1 -1
- package/lib/typescript/src/components/switch/index.d.ts.map +1 -1
- package/lib/typescript/src/components/thinking-orb/index.d.ts +28 -0
- package/lib/typescript/src/components/thinking-orb/index.d.ts.map +1 -0
- package/lib/typescript/src/components/toggle-button/index.d.ts +12 -0
- package/lib/typescript/src/components/toggle-button/index.d.ts.map +1 -1
- package/lib/typescript/src/hooks/index.d.ts +2 -1
- package/lib/typescript/src/hooks/index.d.ts.map +1 -1
- package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts +16 -3
- package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts.map +1 -1
- package/lib/typescript/src/hooks/use-reveal-progress.d.ts +56 -0
- package/lib/typescript/src/hooks/use-reveal-progress.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +6 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/native/index.d.ts +15 -7
- package/lib/typescript/src/native/index.d.ts.map +1 -1
- package/lib/typescript/src/primitives/keyboard-avoider.d.ts +30 -3
- package/lib/typescript/src/primitives/keyboard-avoider.d.ts.map +1 -1
- package/lib/typescript/src/primitives/scroll-progress.d.ts +61 -0
- package/lib/typescript/src/primitives/scroll-progress.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/components/button/index.tsx +13 -11
- package/src/components/chip/index.tsx +333 -0
- package/src/components/frame/index.tsx +39 -50
- package/src/components/heatmap-chart/index.tsx +1024 -0
- package/src/components/input/index.tsx +23 -4
- package/src/components/scroll-canvas/index.tsx +220 -0
- package/src/components/scroll-text/index.tsx +277 -0
- package/src/components/select/index.tsx +4 -9
- package/src/components/slider/index.tsx +4 -7
- package/src/components/switch/index.tsx +5 -8
- package/src/components/thinking-orb/index.tsx +792 -0
- package/src/components/toggle-button/index.tsx +24 -2
- package/src/hooks/index.ts +6 -0
- package/src/hooks/use-keyboard-avoidance.ts +111 -65
- package/src/hooks/use-reveal-progress.ts +106 -0
- package/src/index.ts +46 -0
- package/src/native/index.ts +15 -7
- package/src/primitives/keyboard-avoider.tsx +41 -4
- 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';
|