@cdx-ui/components 0.2.3 → 0.2.5
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/AGENTS.md +24 -0
- package/README.md +2 -0
- package/coverage.svg +1 -1
- package/docs/components/accordion/content.md +538 -0
- package/docs/components/alert/content.md +203 -0
- package/docs/components/alert-dialog/content.md +319 -0
- package/docs/components/avatar/content.md +368 -0
- package/docs/components/avatar/design.md +202 -0
- package/docs/components/badge/content.md +225 -0
- package/docs/components/bottom-sheet/content.md +353 -0
- package/docs/components/bottom-sheet/design.md +249 -0
- package/docs/components/box/content.md +141 -0
- package/docs/components/breadcrumbs/content.md +169 -0
- package/docs/components/button/content.md +398 -0
- package/docs/components/button/design.md +258 -0
- package/docs/components/calendar/content.md +137 -0
- package/docs/components/card/content.md +283 -0
- package/docs/components/carousel/content.md +417 -0
- package/docs/components/checkbox/content.md +236 -0
- package/docs/components/checkbox/design.md +214 -0
- package/docs/components/chip/content.md +439 -0
- package/docs/components/chip/design.md +418 -0
- package/docs/components/color-area/content.md +84 -0
- package/docs/components/color-field/content.md +132 -0
- package/docs/components/color-picker/content.md +209 -0
- package/docs/components/color-slider/content.md +118 -0
- package/docs/components/color-swatch/content.md +62 -0
- package/docs/components/color-swatch-picker/content.md +124 -0
- package/docs/components/content.md +98 -0
- package/docs/components/currency-input/content.md +205 -0
- package/docs/components/data-grid/content.md +521 -0
- package/docs/components/date-field/content.md +147 -0
- package/docs/components/date-picker/content.md +360 -0
- package/docs/components/date-range-picker/content.md +301 -0
- package/docs/components/date-time-field/content.md +157 -0
- package/docs/components/date-time-list/content.md +105 -0
- package/docs/components/date-time-picker/content.md +272 -0
- package/docs/components/dialog/content.md +436 -0
- package/docs/components/dialog/design.md +192 -0
- package/docs/components/divider/content.md +112 -0
- package/docs/components/drawer/content.md +428 -0
- package/docs/components/field/content.md +277 -0
- package/docs/components/form/content.md +62 -0
- package/docs/components/full-screen-dialog/content.md +881 -0
- package/docs/components/heading/content.md +55 -0
- package/docs/components/icon/content.md +190 -0
- package/docs/components/icon-button/content.md +200 -0
- package/docs/components/icon-button/design.md +165 -0
- package/docs/components/image/content.md +104 -0
- package/docs/components/input/content.md +346 -0
- package/docs/components/input/design.md +389 -0
- package/docs/components/insurance-disclosure/content.md +103 -0
- package/docs/components/link/content.md +180 -0
- package/docs/components/link/design.md +160 -0
- package/docs/components/list-item/content.md +695 -0
- package/docs/components/menu/content.md +1254 -0
- package/docs/components/month-calendar/content.md +84 -0
- package/docs/components/month-picker/content.md +273 -0
- package/docs/components/otp-input/content.md +327 -0
- package/docs/components/progress-bar/content.md +87 -0
- package/docs/components/progress-circle/content.md +176 -0
- package/docs/components/progress-segmented/content.md +119 -0
- package/docs/components/quick-action-button/content.md +154 -0
- package/docs/components/quick-action-button/design.md +170 -0
- package/docs/components/radio/content.md +224 -0
- package/docs/components/range-calendar/content.md +123 -0
- package/docs/components/reorderable-list/content.md +311 -0
- package/docs/components/scoped-theme/content.md +47 -0
- package/docs/components/scroll-shadow/content.md +693 -0
- package/docs/components/select/content.md +473 -0
- package/docs/components/select/design.md +301 -0
- package/docs/components/skeleton/content.md +104 -0
- package/docs/components/slider/content.md +423 -0
- package/docs/components/stack/content.md +161 -0
- package/docs/components/switch/content.md +150 -0
- package/docs/components/switch/design.md +208 -0
- package/docs/components/table/content.md +548 -0
- package/docs/components/table-pagination/content.md +177 -0
- package/docs/components/tabs/content.md +297 -0
- package/docs/components/text/content.md +142 -0
- package/docs/components/textarea/content.md +222 -0
- package/docs/components/tile/content.md +702 -0
- package/docs/components/toast/content.md +456 -0
- package/docs/components/toggle-button/content.md +505 -0
- package/docs/components/tooltip/content.md +350 -0
- package/docs/components/virtualized-list/content.md +250 -0
- package/docs/foundations/content.md +9 -0
- package/docs/foundations/expressions/icons/content.md +19 -0
- package/docs/foundations/styles/tokens/all-tokens/content.md +192 -0
- package/docs/foundations/styles/tokens/what-are-tokens/content.md +33 -0
- package/docs/foundations/styles/tokens/what-are-tokens/design.md +33 -0
- package/docs/getting-started/content.md +4 -0
- package/docs/getting-started/designers/content.md +13 -0
- package/docs/getting-started/designers/design.md +13 -0
- package/docs/getting-started/developers/accessibility/content.md +31 -0
- package/docs/getting-started/developers/content.md +612 -0
- package/docs/getting-started/developers/styling/content.md +195 -0
- package/docs/llms.txt +195 -0
- package/docs/patterns/account-management/content.md +75 -0
- package/docs/patterns/authentication/content.md +50 -0
- package/docs/patterns/content.md +10 -0
- package/docs/patterns/dashboard/content.md +34 -0
- package/docs/patterns/empty-states/content.md +32 -0
- package/docs/patterns/forms/content.md +108 -0
- package/docs/patterns/onboarding/content.md +69 -0
- package/docs/patterns/payments/content.md +35 -0
- package/docs/patterns/settings/content.md +72 -0
- package/docs/resources/content.md +9 -0
- package/docs/resources/figma-libraries/content.md +42 -0
- package/docs/resources/release-notes/0.0.1-beta.118/content.md +27 -0
- package/docs/resources/release-notes/0.0.1-beta.122/content.md +21 -0
- package/docs/resources/release-notes/0.0.1-beta.124/content.md +16 -0
- package/docs/resources/release-notes/0.0.1-beta.126/content.md +10 -0
- package/docs/resources/release-notes/0.0.1-beta.127/content.md +14 -0
- package/docs/resources/release-notes/0.0.1-beta.128/content.md +9 -0
- package/docs/resources/release-notes/0.0.1-beta.129/content.md +18 -0
- package/docs/resources/release-notes/0.0.1-beta.130/content.md +18 -0
- package/docs/resources/release-notes/0.0.1-beta.133/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.134/content.md +17 -0
- package/docs/resources/release-notes/0.0.1-beta.136/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.137/content.md +10 -0
- package/docs/resources/release-notes/0.0.1-beta.138/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.139/content.md +13 -0
- package/docs/resources/release-notes/0.0.1-beta.140/content.md +26 -0
- package/docs/resources/release-notes/0.0.1-beta.141/content.md +63 -0
- package/docs/resources/release-notes/0.0.1-beta.142/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.143/content.md +12 -0
- package/docs/resources/release-notes/0.0.1-beta.144/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.145/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.147/content.md +10 -0
- package/docs/resources/release-notes/0.0.1-beta.149/content.md +10 -0
- package/docs/resources/release-notes/0.0.1-beta.150/content.md +13 -0
- package/docs/resources/release-notes/0.0.1-beta.152/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.154/content.md +15 -0
- package/docs/resources/release-notes/0.0.1-beta.156/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.158/content.md +9 -0
- package/docs/resources/release-notes/0.0.1-beta.159/content.md +11 -0
- package/docs/resources/release-notes/0.0.1-beta.160/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.161/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.163/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.164/content.md +9 -0
- package/docs/resources/release-notes/0.0.1-beta.166/content.md +17 -0
- package/docs/resources/release-notes/0.0.1-beta.167/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.168/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.169/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.171/content.md +16 -0
- package/docs/resources/release-notes/0.0.1-beta.172/content.md +24 -0
- package/docs/resources/release-notes/0.0.1-beta.173/content.md +15 -0
- package/docs/resources/release-notes/0.0.1-beta.174/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.176/content.md +32 -0
- package/docs/resources/release-notes/0.0.1-beta.179/content.md +11 -0
- package/docs/resources/release-notes/0.0.1-beta.182/content.md +13 -0
- package/docs/resources/release-notes/0.0.1-beta.185/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.187/content.md +27 -0
- package/docs/resources/release-notes/0.1.1/content.md +23 -0
- package/docs/resources/release-notes/0.1.2/content.md +7 -0
- package/docs/resources/release-notes/0.1.4/content.md +19 -0
- package/docs/resources/release-notes/0.1.5/content.md +7 -0
- package/docs/resources/release-notes/0.1.6/content.md +7 -0
- package/docs/resources/release-notes/0.2.0/content.md +31 -0
- package/docs/resources/release-notes/0.2.1/content.md +17 -0
- package/docs/resources/release-notes/0.2.2/content.md +11 -0
- package/docs/resources/release-notes/0.2.3/content.md +15 -0
- package/docs/resources/release-notes/0.2.4/content.md +17 -0
- package/docs/resources/release-notes/content.md +65 -0
- package/lib/commonjs/components/Box/Box.js +9 -1
- package/lib/commonjs/components/Box/Box.js.map +1 -1
- package/lib/commonjs/components/Breadcrumbs/index.js +28 -3
- package/lib/commonjs/components/Breadcrumbs/index.js.map +1 -1
- package/lib/commonjs/components/Breadcrumbs/styles.js +27 -0
- package/lib/commonjs/components/Breadcrumbs/styles.js.map +1 -1
- package/lib/commonjs/components/DateTimeList/index.js +11 -26
- package/lib/commonjs/components/DateTimeList/index.js.map +1 -1
- package/lib/commonjs/components/DateTimeList/styles.js +2 -12
- package/lib/commonjs/components/DateTimeList/styles.js.map +1 -1
- package/lib/commonjs/components/ListItem/index.js.map +1 -1
- package/lib/commonjs/components/ListItem/styles.js +2 -1
- package/lib/commonjs/components/ListItem/styles.js.map +1 -1
- package/lib/commonjs/components/Menu/index.js +11 -5
- package/lib/commonjs/components/Menu/index.js.map +1 -1
- package/lib/commonjs/components/ScrollShadow/gradient.js +29 -0
- package/lib/commonjs/components/ScrollShadow/gradient.js.map +1 -0
- package/lib/commonjs/components/ScrollShadow/index.js +171 -44
- package/lib/commonjs/components/ScrollShadow/index.js.map +1 -1
- package/lib/commonjs/components/ScrollShadow/styles.js +58 -14
- package/lib/commonjs/components/ScrollShadow/styles.js.map +1 -1
- package/lib/commonjs/components/ScrollShadow/useComposedScrollHandler.js +63 -0
- package/lib/commonjs/components/ScrollShadow/useComposedScrollHandler.js.map +1 -0
- package/lib/commonjs/components/ScrollShadow/useScrollShadow.js +48 -8
- package/lib/commonjs/components/ScrollShadow/useScrollShadow.js.map +1 -1
- package/lib/commonjs/components/Stack/HStack.js +6 -2
- package/lib/commonjs/components/Stack/HStack.js.map +1 -1
- package/lib/commonjs/components/Stack/VStack.js +6 -2
- package/lib/commonjs/components/Stack/VStack.js.map +1 -1
- package/lib/commonjs/components/Tabs/index.js +16 -23
- package/lib/commonjs/components/Tabs/index.js.map +1 -1
- package/lib/commonjs/components/Tabs/styles.js +1 -10
- package/lib/commonjs/components/Tabs/styles.js.map +1 -1
- package/lib/commonjs/figma/ListItem.SectionHeader.figma.js +20 -5
- package/lib/commonjs/figma/ListItem.SectionHeader.figma.js.map +1 -1
- package/lib/commonjs/index.js +10 -10
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/components/Box/Box.js +9 -1
- package/lib/module/components/Box/Box.js.map +1 -1
- package/lib/module/components/Breadcrumbs/index.js +29 -4
- package/lib/module/components/Breadcrumbs/index.js.map +1 -1
- package/lib/module/components/Breadcrumbs/styles.js +26 -0
- package/lib/module/components/Breadcrumbs/styles.js.map +1 -1
- package/lib/module/components/DateTimeList/index.js +12 -27
- package/lib/module/components/DateTimeList/index.js.map +1 -1
- package/lib/module/components/DateTimeList/styles.js +1 -11
- package/lib/module/components/DateTimeList/styles.js.map +1 -1
- package/lib/module/components/ListItem/index.js.map +1 -1
- package/lib/module/components/ListItem/styles.js +2 -1
- package/lib/module/components/ListItem/styles.js.map +1 -1
- package/lib/module/components/Menu/index.js +11 -5
- package/lib/module/components/Menu/index.js.map +1 -1
- package/lib/module/components/ScrollShadow/gradient.js +24 -0
- package/lib/module/components/ScrollShadow/gradient.js.map +1 -0
- package/lib/module/components/ScrollShadow/index.js +170 -48
- package/lib/module/components/ScrollShadow/index.js.map +1 -1
- package/lib/module/components/ScrollShadow/styles.js +57 -13
- package/lib/module/components/ScrollShadow/styles.js.map +1 -1
- package/lib/module/components/ScrollShadow/useComposedScrollHandler.js +57 -0
- package/lib/module/components/ScrollShadow/useComposedScrollHandler.js.map +1 -0
- package/lib/module/components/ScrollShadow/useScrollShadow.js +46 -8
- package/lib/module/components/ScrollShadow/useScrollShadow.js.map +1 -1
- package/lib/module/components/Stack/HStack.js +6 -2
- package/lib/module/components/Stack/HStack.js.map +1 -1
- package/lib/module/components/Stack/VStack.js +6 -2
- package/lib/module/components/Stack/VStack.js.map +1 -1
- package/lib/module/components/Tabs/index.js +17 -24
- package/lib/module/components/Tabs/index.js.map +1 -1
- package/lib/module/components/Tabs/styles.js +0 -9
- package/lib/module/components/Tabs/styles.js.map +1 -1
- package/lib/module/figma/ListItem.SectionHeader.figma.js +20 -5
- package/lib/module/figma/ListItem.SectionHeader.figma.js.map +1 -1
- package/lib/module/index.js +6 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/animation/hooks/usePopupDialogContentAnimation.d.ts +2 -2
- package/lib/typescript/animation/hooks/usePopupOverlayAnimation.d.ts +2 -2
- package/lib/typescript/components/Box/Box.d.ts +4 -0
- package/lib/typescript/components/Box/Box.d.ts.map +1 -1
- package/lib/typescript/components/Breadcrumbs/index.d.ts +3 -1
- package/lib/typescript/components/Breadcrumbs/index.d.ts.map +1 -1
- package/lib/typescript/components/Breadcrumbs/styles.d.ts +2 -0
- package/lib/typescript/components/Breadcrumbs/styles.d.ts.map +1 -1
- package/lib/typescript/components/DateTimeList/index.d.ts.map +1 -1
- package/lib/typescript/components/DateTimeList/styles.d.ts +1 -4
- package/lib/typescript/components/DateTimeList/styles.d.ts.map +1 -1
- package/lib/typescript/components/ListItem/index.d.ts +5 -4
- package/lib/typescript/components/ListItem/index.d.ts.map +1 -1
- package/lib/typescript/components/ListItem/styles.d.ts +1 -1
- package/lib/typescript/components/ListItem/styles.d.ts.map +1 -1
- package/lib/typescript/components/Menu/index.d.ts.map +1 -1
- package/lib/typescript/components/ScrollShadow/gradient.d.ts +7 -0
- package/lib/typescript/components/ScrollShadow/gradient.d.ts.map +1 -0
- package/lib/typescript/components/ScrollShadow/index.d.ts +57 -15
- package/lib/typescript/components/ScrollShadow/index.d.ts.map +1 -1
- package/lib/typescript/components/ScrollShadow/styles.d.ts +8 -2
- package/lib/typescript/components/ScrollShadow/styles.d.ts.map +1 -1
- package/lib/typescript/components/ScrollShadow/useComposedScrollHandler.d.ts +13 -0
- package/lib/typescript/components/ScrollShadow/useComposedScrollHandler.d.ts.map +1 -0
- package/lib/typescript/components/ScrollShadow/useScrollShadow.d.ts +15 -2
- package/lib/typescript/components/ScrollShadow/useScrollShadow.d.ts.map +1 -1
- package/lib/typescript/components/Stack/HStack.d.ts +3 -2
- package/lib/typescript/components/Stack/HStack.d.ts.map +1 -1
- package/lib/typescript/components/Stack/VStack.d.ts +3 -2
- package/lib/typescript/components/Stack/VStack.d.ts.map +1 -1
- package/lib/typescript/components/Tabs/index.d.ts.map +1 -1
- package/lib/typescript/components/Tabs/styles.d.ts +0 -7
- package/lib/typescript/components/Tabs/styles.d.ts.map +1 -1
- package/lib/typescript/components/Toast/animation.d.ts +3 -3
- package/lib/typescript/components/Toast/animation.d.ts.map +1 -1
- package/lib/typescript/figma/ListItem.SectionHeader.figma.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +6 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/package.json +11 -9
- package/src/components/Box/Box.tsx +18 -4
- package/src/components/Breadcrumbs/index.tsx +28 -4
- package/src/components/Breadcrumbs/styles.ts +30 -0
- package/src/components/DateTimeList/index.tsx +13 -26
- package/src/components/DateTimeList/styles.ts +1 -10
- package/src/components/ListItem/index.tsx +5 -4
- package/src/components/ListItem/styles.ts +1 -0
- package/src/components/Menu/index.tsx +11 -8
- package/src/components/ScrollShadow/gradient.ts +48 -0
- package/src/components/ScrollShadow/index.tsx +300 -69
- package/src/components/ScrollShadow/styles.ts +45 -28
- package/src/components/ScrollShadow/useComposedScrollHandler.ts +58 -0
- package/src/components/ScrollShadow/useScrollShadow.ts +72 -10
- package/src/components/Stack/HStack.tsx +8 -4
- package/src/components/Stack/VStack.tsx +8 -4
- package/src/components/Tabs/index.tsx +25 -35
- package/src/components/Tabs/styles.ts +0 -9
- package/src/index.ts +8 -1
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
type IMenuTriggerProps,
|
|
36
36
|
} from '@cdx-ui/primitives';
|
|
37
37
|
import { cn, ParentContext, useParentContext, useStyleContext } from '@cdx-ui/utils';
|
|
38
|
+
import { ScrollShadow } from '../ScrollShadow';
|
|
38
39
|
import { Icon, type IconProps } from '../Icon';
|
|
39
40
|
import { checkboxIconVariants, checkboxIndicatorVariants } from '../Checkbox/styles';
|
|
40
41
|
import { radioIndicatorVariants, radioInnerDotVariants } from '../Radio/styles';
|
|
@@ -222,14 +223,16 @@ const MenuContent = forwardRef<View, MenuContentProps>(
|
|
|
222
223
|
: mergeDataAttributes(props, dataAttributes({ slot: 'menu-content' }));
|
|
223
224
|
|
|
224
225
|
const content = shouldScroll ? (
|
|
225
|
-
<
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
226
|
+
<ScrollShadow className="shrink" style={constrainedStyle} surface="primary">
|
|
227
|
+
<ScrollView
|
|
228
|
+
className="shrink"
|
|
229
|
+
style={[MENU_SCROLL_STYLE, constrainedStyle]}
|
|
230
|
+
scrollEventThrottle={16}
|
|
231
|
+
nestedScrollEnabled
|
|
232
|
+
>
|
|
233
|
+
{children}
|
|
234
|
+
</ScrollView>
|
|
235
|
+
</ScrollShadow>
|
|
233
236
|
) : (
|
|
234
237
|
children
|
|
235
238
|
);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { I18nManager } from 'react-native';
|
|
2
|
+
import { SCROLL_SHADOW_SURFACE_FROM_CLASS, type ScrollShadowSurface } from './styles';
|
|
3
|
+
|
|
4
|
+
type ScrollShadowEdge = 'start' | 'end';
|
|
5
|
+
type ScrollShadowOrientation = 'horizontal' | 'vertical';
|
|
6
|
+
|
|
7
|
+
export function getWebSurfaceGradientClasses(
|
|
8
|
+
surface: ScrollShadowSurface,
|
|
9
|
+
orientation: ScrollShadowOrientation,
|
|
10
|
+
edge: ScrollShadowEdge,
|
|
11
|
+
): string {
|
|
12
|
+
const fromClass = SCROLL_SHADOW_SURFACE_FROM_CLASS[surface];
|
|
13
|
+
|
|
14
|
+
if (orientation === 'vertical') {
|
|
15
|
+
return edge === 'start'
|
|
16
|
+
? `bg-gradient-to-b ${fromClass} to-transparent`
|
|
17
|
+
: `bg-gradient-to-t ${fromClass} to-transparent`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ltr:/rtl: so the fade flips with layout direction on the first paint,
|
|
21
|
+
// not after a later scroll re-render.
|
|
22
|
+
return edge === 'start'
|
|
23
|
+
? `ltr:bg-gradient-to-r rtl:bg-gradient-to-l ${fromClass} to-transparent`
|
|
24
|
+
: `ltr:bg-gradient-to-l rtl:bg-gradient-to-r ${fromClass} to-transparent`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getInlineBackgroundImage(
|
|
28
|
+
color: string,
|
|
29
|
+
orientation: ScrollShadowOrientation,
|
|
30
|
+
edge: ScrollShadowEdge,
|
|
31
|
+
isRTL = I18nManager.isRTL,
|
|
32
|
+
): string {
|
|
33
|
+
if (orientation === 'vertical') {
|
|
34
|
+
return edge === 'start'
|
|
35
|
+
? `linear-gradient(to bottom, ${color}, transparent)`
|
|
36
|
+
: `linear-gradient(to top, ${color}, transparent)`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (isRTL) {
|
|
40
|
+
return edge === 'start'
|
|
41
|
+
? `linear-gradient(to left, ${color}, transparent)`
|
|
42
|
+
: `linear-gradient(to right, ${color}, transparent)`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return edge === 'start'
|
|
46
|
+
? `linear-gradient(to right, ${color}, transparent)`
|
|
47
|
+
: `linear-gradient(to left, ${color}, transparent)`;
|
|
48
|
+
}
|
|
@@ -1,119 +1,350 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
Children,
|
|
3
|
+
cloneElement,
|
|
4
|
+
isValidElement,
|
|
5
|
+
useCallback,
|
|
6
|
+
useRef,
|
|
7
|
+
type ReactElement,
|
|
8
|
+
} from 'react';
|
|
9
|
+
import { Animated, Platform, StyleSheet, View, type StyleProp, type ViewStyle } from 'react-native';
|
|
10
|
+
import { useCSSVariable, useResolveClassNames } from 'uniwind';
|
|
11
|
+
import { dataAttributes, mergeDataAttributes } from '@cdx-ui/primitives';
|
|
3
12
|
import { cn } from '@cdx-ui/utils';
|
|
13
|
+
import { getInlineBackgroundImage, getWebSurfaceGradientClasses } from './gradient';
|
|
4
14
|
import {
|
|
15
|
+
SCROLL_SHADOW_SIZE_PX,
|
|
16
|
+
SCROLL_SHADOW_SURFACE_CSS_VARS,
|
|
5
17
|
scrollShadowContainerVariants,
|
|
6
|
-
|
|
18
|
+
scrollShadowEdgeVariants,
|
|
7
19
|
scrollShadowVariants,
|
|
20
|
+
type ScrollShadowSize,
|
|
21
|
+
type ScrollShadowSurface,
|
|
8
22
|
type ScrollShadowVariantProps,
|
|
9
23
|
} from './styles';
|
|
10
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
composeScrollHandler,
|
|
26
|
+
isReanimatedScrollHandler,
|
|
27
|
+
useReanimatedComposedScrollHandler,
|
|
28
|
+
} from './useComposedScrollHandler';
|
|
29
|
+
import {
|
|
30
|
+
useScrollShadowTracker,
|
|
31
|
+
type ScrollShadowCapability,
|
|
32
|
+
type ScrollShadowDistance,
|
|
33
|
+
type UseScrollShadowReturn,
|
|
34
|
+
} from './useScrollShadow';
|
|
35
|
+
|
|
36
|
+
export type {
|
|
37
|
+
ScrollShadowCapability,
|
|
38
|
+
UseScrollShadowOptions,
|
|
39
|
+
UseScrollShadowReturn,
|
|
40
|
+
} from './useScrollShadow';
|
|
41
|
+
export { useScrollShadow } from './useScrollShadow';
|
|
11
42
|
|
|
12
|
-
export type
|
|
43
|
+
export type ScrollShadowVisibility = 'auto' | 'both' | 'start' | 'end' | 'none';
|
|
13
44
|
|
|
14
45
|
export interface ScrollShadowProps extends ScrollShadowVariantProps {
|
|
15
|
-
|
|
46
|
+
/**
|
|
47
|
+
* The scroll view to decorate: a `ScrollView`, `FlatList`, or `VirtualizedList`, passed as
|
|
48
|
+
* the direct child. With a forced `visibility`, any single view works.
|
|
49
|
+
*/
|
|
50
|
+
children: ReactElement;
|
|
51
|
+
/** Classes for the wrapping view, for example `h-full` or `flex-1` to bound the scroller. */
|
|
16
52
|
className?: string;
|
|
53
|
+
/** Style for the wrapping view. */
|
|
54
|
+
style?: StyleProp<ViewStyle>;
|
|
17
55
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* @default 'from-background/35'
|
|
56
|
+
* Scroll axis that gets fades.
|
|
57
|
+
* @default inferred from the child's `horizontal` prop, otherwise `'vertical'`
|
|
21
58
|
*/
|
|
22
|
-
|
|
59
|
+
orientation?: 'horizontal' | 'vertical';
|
|
23
60
|
/**
|
|
24
|
-
*
|
|
25
|
-
* @default
|
|
61
|
+
* Theme surface the fade blends into. Match it to the background behind the scroller.
|
|
62
|
+
* @default 'background'
|
|
26
63
|
*/
|
|
27
|
-
|
|
64
|
+
surface?: ScrollShadowSurface;
|
|
28
65
|
/**
|
|
29
|
-
*
|
|
66
|
+
* Fade depth along the scroll axis: `small` is 32px, `default` is 40px, `large` is 72px.
|
|
67
|
+
* @default 'default'
|
|
68
|
+
*/
|
|
69
|
+
size?: ScrollShadowSize;
|
|
70
|
+
/**
|
|
71
|
+
* Which edges show a fade. `auto` follows the scroll position; `both`, `start`, and `end`
|
|
72
|
+
* force those edges on; `none` hides them.
|
|
73
|
+
* @default 'auto'
|
|
74
|
+
*/
|
|
75
|
+
visibility?: ScrollShadowVisibility;
|
|
76
|
+
/**
|
|
77
|
+
* Pixels of scroll slack before an edge counts as scrollable. Only used with `auto`.
|
|
30
78
|
* @default 0
|
|
31
79
|
*/
|
|
32
80
|
offset?: number;
|
|
81
|
+
/**
|
|
82
|
+
* Hides the child's scrollbar on web. On iOS and Android, set
|
|
83
|
+
* `showsVerticalScrollIndicator` or `showsHorizontalScrollIndicator` on the child instead.
|
|
84
|
+
* @default false
|
|
85
|
+
*/
|
|
86
|
+
hideScrollBar?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Width, opacity, or position overrides for the fade overlays, applied after `size`, for
|
|
89
|
+
* example `w-24` or `opacity-85`. Must not carry color classes; use `surface` or
|
|
90
|
+
* `colorClassName` instead.
|
|
91
|
+
*/
|
|
92
|
+
edgeClassName?: string;
|
|
93
|
+
/**
|
|
94
|
+
* One-off fade color outside the `surface` options, as an `accent-*` class. Overrides
|
|
95
|
+
* `surface` on every platform and follows dark mode and `ScopedTheme`.
|
|
96
|
+
*/
|
|
97
|
+
colorClassName?: string;
|
|
98
|
+
/**
|
|
99
|
+
* Called when either edge starts or stops being scrollable, with
|
|
100
|
+
* `{ canScrollBefore, canScrollAfter }`. Only fires with `visibility="auto"`.
|
|
101
|
+
*/
|
|
33
102
|
onCapabilityChange?: (capability: ScrollShadowCapability) => void;
|
|
34
|
-
style?: ViewStyle;
|
|
35
103
|
}
|
|
36
104
|
|
|
37
105
|
interface ScrollShadowChildProps {
|
|
38
106
|
className?: string;
|
|
39
|
-
|
|
40
|
-
|
|
107
|
+
horizontal?: boolean;
|
|
108
|
+
style?: StyleProp<ViewStyle>;
|
|
109
|
+
scrollEventThrottle?: number;
|
|
110
|
+
onLayout?: (event: Parameters<UseScrollShadowReturn['handleLayout']>[0]) => void;
|
|
41
111
|
onContentSizeChange?: (width: number, height: number) => void;
|
|
42
|
-
onScroll?:
|
|
112
|
+
onScroll?: unknown;
|
|
43
113
|
ref?: React.Ref<unknown>;
|
|
44
114
|
}
|
|
45
115
|
|
|
116
|
+
interface ScrollShadowEdgeProps {
|
|
117
|
+
edge: 'start' | 'end';
|
|
118
|
+
orientation: 'horizontal' | 'vertical';
|
|
119
|
+
size: ScrollShadowSize;
|
|
120
|
+
surface: ScrollShadowSurface;
|
|
121
|
+
colorClassName?: string;
|
|
122
|
+
edgeClassName?: string;
|
|
123
|
+
opacity?: Animated.Value;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function ScrollShadowEdge({
|
|
127
|
+
edge,
|
|
128
|
+
orientation,
|
|
129
|
+
size,
|
|
130
|
+
surface,
|
|
131
|
+
colorClassName,
|
|
132
|
+
edgeClassName,
|
|
133
|
+
opacity,
|
|
134
|
+
}: ScrollShadowEdgeProps) {
|
|
135
|
+
const surfaceColor = useCSSVariable(SCROLL_SHADOW_SURFACE_CSS_VARS[surface]) || 'transparent';
|
|
136
|
+
const resolvedColorClassName = useResolveClassNames(colorClassName ?? '');
|
|
137
|
+
const customColor =
|
|
138
|
+
colorClassName != null
|
|
139
|
+
? (resolvedColorClassName.accentColor ?? resolvedColorClassName.backgroundColor)
|
|
140
|
+
: undefined;
|
|
141
|
+
|
|
142
|
+
if (__DEV__ && colorClassName != null && customColor == null) {
|
|
143
|
+
console.warn(
|
|
144
|
+
`[ScrollShadow] colorClassName "${colorClassName}" did not resolve to a color. Falling back to surface="${surface}".`,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const isWeb = Platform.OS === 'web';
|
|
149
|
+
// Web paints built-in surfaces with static classes; a custom color has no static class,
|
|
150
|
+
// so it takes a CSS background-image (experimental_backgroundImage paints nothing on RNW).
|
|
151
|
+
const useInlinePath = !isWeb || customColor != null;
|
|
152
|
+
const inlineGradient = useInlinePath
|
|
153
|
+
? getInlineBackgroundImage(String(customColor ?? surfaceColor), orientation, edge, false)
|
|
154
|
+
: undefined;
|
|
155
|
+
const webGradientClasses = useInlinePath
|
|
156
|
+
? undefined
|
|
157
|
+
: getWebSurfaceGradientClasses(surface, orientation, edge);
|
|
158
|
+
const inlineStyle = inlineGradient
|
|
159
|
+
? isWeb
|
|
160
|
+
? ({ backgroundImage: inlineGradient } as unknown as ViewStyle)
|
|
161
|
+
: { experimental_backgroundImage: inlineGradient }
|
|
162
|
+
: undefined;
|
|
163
|
+
|
|
164
|
+
const edgeView = (
|
|
165
|
+
<View
|
|
166
|
+
pointerEvents="none"
|
|
167
|
+
accessible={false}
|
|
168
|
+
accessibilityElementsHidden
|
|
169
|
+
importantForAccessibility="no-hide-descendants"
|
|
170
|
+
aria-hidden
|
|
171
|
+
className={cn(
|
|
172
|
+
scrollShadowEdgeVariants({ orientation, edge, size }),
|
|
173
|
+
// The inline gradient is authored LTR; mirroring follows Uniwind's layout
|
|
174
|
+
// direction (I18nManager or LayoutDirection) without a re-render.
|
|
175
|
+
useInlinePath && orientation === 'horizontal' ? 'rtl:-scale-x-100' : undefined,
|
|
176
|
+
webGradientClasses,
|
|
177
|
+
edgeClassName,
|
|
178
|
+
)}
|
|
179
|
+
style={inlineStyle}
|
|
180
|
+
{...mergeDataAttributes(dataAttributes({ slot: 'scroll-shadow-edge', edge }))}
|
|
181
|
+
/>
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
if (!opacity) {
|
|
185
|
+
return edgeView;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return (
|
|
189
|
+
<Animated.View
|
|
190
|
+
pointerEvents="none"
|
|
191
|
+
accessible={false}
|
|
192
|
+
accessibilityElementsHidden
|
|
193
|
+
importantForAccessibility="no-hide-descendants"
|
|
194
|
+
aria-hidden
|
|
195
|
+
style={[StyleSheet.absoluteFill, { opacity }]}
|
|
196
|
+
>
|
|
197
|
+
{edgeView}
|
|
198
|
+
</Animated.View>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function shouldShowEdge(
|
|
203
|
+
visibility: ScrollShadowVisibility,
|
|
204
|
+
edge: 'start' | 'end',
|
|
205
|
+
capability: ScrollShadowCapability,
|
|
206
|
+
): boolean {
|
|
207
|
+
switch (visibility) {
|
|
208
|
+
case 'both':
|
|
209
|
+
return true;
|
|
210
|
+
case 'start':
|
|
211
|
+
return edge === 'start';
|
|
212
|
+
case 'end':
|
|
213
|
+
return edge === 'end';
|
|
214
|
+
case 'none':
|
|
215
|
+
return false;
|
|
216
|
+
case 'auto':
|
|
217
|
+
default:
|
|
218
|
+
return edge === 'start' ? capability.canScrollBefore : capability.canScrollAfter;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function ReanimatedTrackedChild({
|
|
223
|
+
child,
|
|
224
|
+
handleScroll,
|
|
225
|
+
trackedChildProps,
|
|
226
|
+
}: {
|
|
227
|
+
child: ReactElement<ScrollShadowChildProps>;
|
|
228
|
+
handleScroll: UseScrollShadowReturn['handleScroll'];
|
|
229
|
+
trackedChildProps: ScrollShadowChildProps;
|
|
230
|
+
}) {
|
|
231
|
+
const onScroll = useReanimatedComposedScrollHandler(handleScroll, child.props.onScroll);
|
|
232
|
+
|
|
233
|
+
return cloneElement(child, {
|
|
234
|
+
...trackedChildProps,
|
|
235
|
+
onScroll,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
46
239
|
export function ScrollShadow({
|
|
47
240
|
children,
|
|
48
241
|
className,
|
|
49
|
-
|
|
242
|
+
style,
|
|
243
|
+
surface = 'background',
|
|
244
|
+
size = 'default',
|
|
245
|
+
visibility = 'auto',
|
|
50
246
|
hideScrollBar = false,
|
|
51
|
-
orientation
|
|
247
|
+
orientation,
|
|
52
248
|
offset = 0,
|
|
249
|
+
edgeClassName,
|
|
250
|
+
colorClassName,
|
|
53
251
|
onCapabilityChange,
|
|
54
|
-
size = 64,
|
|
55
|
-
style,
|
|
56
252
|
}: ScrollShadowProps) {
|
|
57
|
-
const resolvedOrientation = orientation ?? 'horizontal';
|
|
58
253
|
const child = Children.only(children);
|
|
59
254
|
|
|
60
255
|
if (!isValidElement<ScrollShadowChildProps>(child)) {
|
|
61
256
|
throw new Error('ScrollShadow expects a single React element child.');
|
|
62
257
|
}
|
|
63
258
|
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
259
|
+
const resolvedOrientation = orientation ?? (child.props.horizontal ? 'horizontal' : 'vertical');
|
|
260
|
+
const trackingEnabled = visibility === 'auto';
|
|
261
|
+
|
|
262
|
+
const startOpacity = useRef(new Animated.Value(0)).current;
|
|
263
|
+
const endOpacity = useRef(new Animated.Value(0)).current;
|
|
264
|
+
const fadeDistance = SCROLL_SHADOW_SIZE_PX[size];
|
|
69
265
|
|
|
70
|
-
|
|
71
|
-
|
|
266
|
+
// Opacity tracks the distance to each edge, so the fade eases out over the last
|
|
267
|
+
// `fadeDistance` px of scroll instead of cutting when the edge is reached.
|
|
268
|
+
const handleDistanceChange = useCallback(
|
|
269
|
+
({ before, after }: ScrollShadowDistance) => {
|
|
270
|
+
startOpacity.setValue(Math.min(1, before / fadeDistance));
|
|
271
|
+
endOpacity.setValue(Math.min(1, after / fadeDistance));
|
|
272
|
+
},
|
|
273
|
+
[startOpacity, endOpacity, fadeDistance],
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
const { capability, handleContentSizeChange, handleLayout, handleScroll } =
|
|
277
|
+
useScrollShadowTracker({
|
|
278
|
+
offset,
|
|
279
|
+
onCapabilityChange,
|
|
280
|
+
onDistanceChange: handleDistanceChange,
|
|
281
|
+
orientation: resolvedOrientation,
|
|
282
|
+
enabled: trackingEnabled,
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const showStart = shouldShowEdge(visibility, 'start', capability);
|
|
286
|
+
const showEnd = shouldShowEdge(visibility, 'end', capability);
|
|
287
|
+
const useReanimatedScroll = isReanimatedScrollHandler(child.props.onScroll);
|
|
288
|
+
|
|
289
|
+
const trackedChildProps: ScrollShadowChildProps = {
|
|
290
|
+
className: cn(scrollShadowVariants({ hideScrollBar }), child.props.className),
|
|
291
|
+
// Keep measuring while visibility is forced so a switch back to auto fades
|
|
292
|
+
// from the scroll position the user already reached.
|
|
293
|
+
onContentSizeChange: (width: number, height: number) => {
|
|
294
|
+
handleContentSizeChange(width, height);
|
|
295
|
+
child.props.onContentSizeChange?.(width, height);
|
|
296
|
+
},
|
|
297
|
+
onLayout: (event) => {
|
|
298
|
+
handleLayout(event);
|
|
299
|
+
child.props.onLayout?.(event);
|
|
300
|
+
},
|
|
301
|
+
...(useReanimatedScroll
|
|
302
|
+
? {}
|
|
303
|
+
: {
|
|
304
|
+
onScroll: composeScrollHandler(handleScroll, child.props.onScroll),
|
|
305
|
+
}),
|
|
306
|
+
...(child.props.scrollEventThrottle === undefined ? { scrollEventThrottle: 16 } : {}),
|
|
307
|
+
};
|
|
72
308
|
|
|
73
309
|
return (
|
|
74
|
-
<View
|
|
75
|
-
{
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
edge: 'start',
|
|
98
|
-
}),
|
|
99
|
-
overlayFade,
|
|
100
|
-
)}
|
|
101
|
-
style={overlayAxisSize}
|
|
310
|
+
<View
|
|
311
|
+
className={cn(scrollShadowContainerVariants(), className)}
|
|
312
|
+
style={style}
|
|
313
|
+
{...mergeDataAttributes(dataAttributes({ slot: 'scroll-shadow' }))}
|
|
314
|
+
>
|
|
315
|
+
{useReanimatedScroll ? (
|
|
316
|
+
<ReanimatedTrackedChild
|
|
317
|
+
child={child}
|
|
318
|
+
handleScroll={handleScroll}
|
|
319
|
+
trackedChildProps={trackedChildProps}
|
|
320
|
+
/>
|
|
321
|
+
) : (
|
|
322
|
+
cloneElement(child, trackedChildProps)
|
|
323
|
+
)}
|
|
324
|
+
{showStart ? (
|
|
325
|
+
<ScrollShadowEdge
|
|
326
|
+
colorClassName={colorClassName}
|
|
327
|
+
edge="start"
|
|
328
|
+
edgeClassName={edgeClassName}
|
|
329
|
+
opacity={trackingEnabled ? startOpacity : undefined}
|
|
330
|
+
orientation={resolvedOrientation}
|
|
331
|
+
size={size}
|
|
332
|
+
surface={surface}
|
|
102
333
|
/>
|
|
103
334
|
) : null}
|
|
104
|
-
{
|
|
105
|
-
<
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
)}
|
|
114
|
-
style={overlayAxisSize}
|
|
335
|
+
{showEnd ? (
|
|
336
|
+
<ScrollShadowEdge
|
|
337
|
+
colorClassName={colorClassName}
|
|
338
|
+
edge="end"
|
|
339
|
+
edgeClassName={edgeClassName}
|
|
340
|
+
opacity={trackingEnabled ? endOpacity : undefined}
|
|
341
|
+
orientation={resolvedOrientation}
|
|
342
|
+
size={size}
|
|
343
|
+
surface={surface}
|
|
115
344
|
/>
|
|
116
345
|
) : null}
|
|
117
346
|
</View>
|
|
118
347
|
);
|
|
119
348
|
}
|
|
349
|
+
|
|
350
|
+
ScrollShadow.displayName = 'ScrollShadow';
|
|
@@ -1,57 +1,74 @@
|
|
|
1
1
|
import { cva, type VariantProps } from '@cdx-ui/utils';
|
|
2
2
|
|
|
3
|
+
export type ScrollShadowSurface = 'background' | 'primary' | 'secondary';
|
|
4
|
+
export type ScrollShadowSize = 'small' | 'default' | 'large';
|
|
5
|
+
|
|
6
|
+
export const SCROLL_SHADOW_SURFACE_CSS_VARS: Record<ScrollShadowSurface, string> = {
|
|
7
|
+
background: '--color-surface-background',
|
|
8
|
+
primary: '--color-surface-primary',
|
|
9
|
+
secondary: '--color-surface-secondary',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const SCROLL_SHADOW_SIZE_PX: Record<ScrollShadowSize, number> = {
|
|
13
|
+
small: 32,
|
|
14
|
+
default: 40,
|
|
15
|
+
large: 72,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const SCROLL_SHADOW_SURFACE_FROM_CLASS: Record<ScrollShadowSurface, string> = {
|
|
19
|
+
background: 'from-surface-background',
|
|
20
|
+
primary: 'from-surface-primary',
|
|
21
|
+
secondary: 'from-surface-secondary',
|
|
22
|
+
};
|
|
23
|
+
|
|
3
24
|
export const scrollShadowVariants = cva([], {
|
|
4
25
|
variants: {
|
|
5
|
-
orientation: {
|
|
6
|
-
horizontal: '',
|
|
7
|
-
vertical: '',
|
|
8
|
-
},
|
|
9
26
|
hideScrollBar: {
|
|
10
27
|
true: 'web:[scrollbar-width:none] web:[&::-webkit-scrollbar]:hidden',
|
|
11
28
|
false: '',
|
|
12
29
|
},
|
|
13
30
|
},
|
|
14
31
|
defaultVariants: {
|
|
15
|
-
orientation: 'horizontal',
|
|
16
32
|
hideScrollBar: false,
|
|
17
33
|
},
|
|
18
34
|
});
|
|
19
35
|
|
|
20
36
|
export const scrollShadowContainerVariants = cva('relative min-w-0 w-full');
|
|
21
37
|
|
|
22
|
-
export const
|
|
38
|
+
export const scrollShadowEdgeVariants = cva('pointer-events-none absolute z-10', {
|
|
23
39
|
variants: {
|
|
24
40
|
orientation: {
|
|
25
|
-
horizontal: '',
|
|
26
|
-
vertical: '',
|
|
41
|
+
horizontal: 'top-0 bottom-0',
|
|
42
|
+
vertical: 'start-0 end-0',
|
|
27
43
|
},
|
|
28
44
|
edge: {
|
|
29
45
|
start: '',
|
|
30
46
|
end: '',
|
|
31
47
|
},
|
|
48
|
+
size: {
|
|
49
|
+
small: '',
|
|
50
|
+
default: '',
|
|
51
|
+
large: '',
|
|
52
|
+
},
|
|
32
53
|
},
|
|
33
54
|
compoundVariants: [
|
|
34
|
-
{
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
orientation: 'vertical',
|
|
46
|
-
edge: 'start',
|
|
47
|
-
className: 'left-0 right-0 top-0 bg-gradient-to-b',
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
orientation: 'vertical',
|
|
51
|
-
edge: 'end',
|
|
52
|
-
className: 'left-0 right-0 bottom-0 bg-gradient-to-t',
|
|
53
|
-
},
|
|
55
|
+
{ orientation: 'horizontal', edge: 'start', className: 'start-0' },
|
|
56
|
+
{ orientation: 'horizontal', edge: 'end', className: 'end-0' },
|
|
57
|
+
{ orientation: 'vertical', edge: 'start', className: 'top-0' },
|
|
58
|
+
{ orientation: 'vertical', edge: 'end', className: 'bottom-0' },
|
|
59
|
+
{ orientation: 'horizontal', size: 'small', className: 'w-8' },
|
|
60
|
+
{ orientation: 'horizontal', size: 'default', className: 'w-10' },
|
|
61
|
+
{ orientation: 'horizontal', size: 'large', className: 'w-18' },
|
|
62
|
+
{ orientation: 'vertical', size: 'small', className: 'h-8' },
|
|
63
|
+
{ orientation: 'vertical', size: 'default', className: 'h-10' },
|
|
64
|
+
{ orientation: 'vertical', size: 'large', className: 'h-18' },
|
|
54
65
|
],
|
|
66
|
+
defaultVariants: {
|
|
67
|
+
orientation: 'vertical',
|
|
68
|
+
edge: 'start',
|
|
69
|
+
size: 'default',
|
|
70
|
+
},
|
|
55
71
|
});
|
|
56
72
|
|
|
57
73
|
export type ScrollShadowVariantProps = VariantProps<typeof scrollShadowVariants>;
|
|
74
|
+
export type ScrollShadowEdgeVariantProps = VariantProps<typeof scrollShadowEdgeVariants>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { useRef } from 'react';
|
|
2
|
+
import type { NativeScrollEvent, NativeSyntheticEvent } from 'react-native';
|
|
3
|
+
import { useAnimatedScrollHandler, useComposedEventHandler } from 'react-native-reanimated';
|
|
4
|
+
import { scheduleOnRN } from 'react-native-worklets';
|
|
5
|
+
import { composeEventHandlers } from '@cdx-ui/utils';
|
|
6
|
+
|
|
7
|
+
type ScrollHandler = (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
|
|
8
|
+
|
|
9
|
+
export function isReanimatedScrollHandler(handler: unknown): boolean {
|
|
10
|
+
return handler != null && typeof handler !== 'function';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function composeScrollHandler(
|
|
14
|
+
internalHandler: ScrollHandler,
|
|
15
|
+
externalHandler: unknown,
|
|
16
|
+
): ScrollHandler {
|
|
17
|
+
if (typeof externalHandler === 'function') {
|
|
18
|
+
return composeEventHandlers(internalHandler, externalHandler as ScrollHandler);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return internalHandler;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Only call this when the child already passed a Reanimated scroll handler.
|
|
26
|
+
* `useAnimatedScrollHandler` requires a Babel worklet, and the published
|
|
27
|
+
* package is not transformed by that plugin, so the plain ScrollView path
|
|
28
|
+
* must not mount this hook.
|
|
29
|
+
*/
|
|
30
|
+
export function useReanimatedComposedScrollHandler(
|
|
31
|
+
internalHandler: ScrollHandler,
|
|
32
|
+
externalHandler: unknown,
|
|
33
|
+
): unknown {
|
|
34
|
+
const internalHandlerRef = useRef(internalHandler);
|
|
35
|
+
internalHandlerRef.current = internalHandler;
|
|
36
|
+
|
|
37
|
+
const internalAnimatedHandler = useAnimatedScrollHandler({
|
|
38
|
+
onScroll: (event) => {
|
|
39
|
+
'worklet';
|
|
40
|
+
// The UI-thread event is a host object. Copy the numbers scheduleOnRN can
|
|
41
|
+
// serialize; passing the event itself drops contentOffset and contentSize.
|
|
42
|
+
const { contentOffset, contentSize, layoutMeasurement } = event;
|
|
43
|
+
|
|
44
|
+
scheduleOnRN(internalHandlerRef.current, {
|
|
45
|
+
nativeEvent: {
|
|
46
|
+
contentOffset: { x: contentOffset.x, y: contentOffset.y },
|
|
47
|
+
contentSize: { width: contentSize.width, height: contentSize.height },
|
|
48
|
+
layoutMeasurement: {
|
|
49
|
+
width: layoutMeasurement.width,
|
|
50
|
+
height: layoutMeasurement.height,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
} as NativeSyntheticEvent<NativeScrollEvent>);
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return useComposedEventHandler([externalHandler as never, internalAnimatedHandler]);
|
|
58
|
+
}
|