react-native-terra-ui 0.11.10 → 0.11.12
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/CHANGELOG.md +17 -0
- package/lib/module/components/box/Box.js +35 -10
- package/lib/module/components/box/Box.js.map +1 -1
- package/lib/module/components/header/hooks/use-header-color.js +16 -0
- package/lib/module/components/header/hooks/use-header-color.js.map +1 -0
- package/lib/module/components/header/hooks/use-large-title-header.js +81 -0
- package/lib/module/components/header/hooks/use-large-title-header.js.map +1 -0
- package/lib/module/components/header/parts/HeaderAccessory.js +21 -6
- package/lib/module/components/header/parts/HeaderAccessory.js.map +1 -1
- package/lib/module/components/header/parts/HeaderBar.js +122 -0
- package/lib/module/components/header/parts/HeaderBar.js.map +1 -0
- package/lib/module/components/header/parts/HeaderGradientOverlay.js +20 -76
- package/lib/module/components/header/parts/HeaderGradientOverlay.js.map +1 -1
- package/lib/module/components/header/parts/HeaderSurface.js +16 -37
- package/lib/module/components/header/parts/HeaderSurface.js.map +1 -1
- package/lib/module/components/header/variants/LargeTitleHeader/index.js +51 -388
- package/lib/module/components/header/variants/LargeTitleHeader/index.js.map +1 -1
- package/lib/module/components/header/variants/LargeTitleHeader/parts/LargeTitleContent.js +72 -0
- package/lib/module/components/header/variants/LargeTitleHeader/parts/LargeTitleContent.js.map +1 -0
- package/lib/module/components/header/variants/TitleHeader/index.js +32 -161
- package/lib/module/components/header/variants/TitleHeader/index.js.map +1 -1
- package/lib/module/components/surface/Surface.js +2 -0
- package/lib/module/components/surface/Surface.js.map +1 -1
- package/lib/typescript/src/components/box/Box.d.ts +28 -4
- package/lib/typescript/src/components/box/Box.d.ts.map +1 -1
- package/lib/typescript/src/components/header/hooks/use-header-color.d.ts +4 -0
- package/lib/typescript/src/components/header/hooks/use-header-color.d.ts.map +1 -0
- package/lib/typescript/src/components/header/hooks/use-large-title-header.d.ts +36 -0
- package/lib/typescript/src/components/header/hooks/use-large-title-header.d.ts.map +1 -0
- package/lib/typescript/src/components/header/parts/HeaderAccessory.d.ts +8 -5
- package/lib/typescript/src/components/header/parts/HeaderAccessory.d.ts.map +1 -1
- package/lib/typescript/src/components/header/parts/HeaderBar.d.ts +17 -0
- package/lib/typescript/src/components/header/parts/HeaderBar.d.ts.map +1 -0
- package/lib/typescript/src/components/header/parts/HeaderGradientOverlay.d.ts +12 -15
- package/lib/typescript/src/components/header/parts/HeaderGradientOverlay.d.ts.map +1 -1
- package/lib/typescript/src/components/header/parts/HeaderSurface.d.ts +8 -9
- package/lib/typescript/src/components/header/parts/HeaderSurface.d.ts.map +1 -1
- package/lib/typescript/src/components/header/variants/LargeTitleHeader/index.d.ts +3 -23
- package/lib/typescript/src/components/header/variants/LargeTitleHeader/index.d.ts.map +1 -1
- package/lib/typescript/src/components/header/variants/LargeTitleHeader/parts/LargeTitleContent.d.ts +11 -0
- package/lib/typescript/src/components/header/variants/LargeTitleHeader/parts/LargeTitleContent.d.ts.map +1 -0
- package/lib/typescript/src/components/header/variants/TitleHeader/index.d.ts +3 -19
- package/lib/typescript/src/components/header/variants/TitleHeader/index.d.ts.map +1 -1
- package/lib/typescript/src/components/surface/Surface.d.ts +1 -1
- package/lib/typescript/src/components/surface/Surface.d.ts.map +1 -1
- package/lib/typescript/src/components/toast/Toast.d.ts +1 -1
- package/lib/typescript/src/components/toast/Toast.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/box/Box.tsx +59 -16
- package/src/components/header/hooks/use-header-color.ts +14 -0
- package/src/components/header/hooks/use-large-title-header.ts +78 -0
- package/src/components/header/parts/HeaderAccessory.tsx +26 -7
- package/src/components/header/parts/HeaderBar.tsx +125 -0
- package/src/components/header/parts/HeaderGradientOverlay.tsx +18 -70
- package/src/components/header/parts/HeaderSurface.tsx +16 -35
- package/src/components/header/variants/LargeTitleHeader/index.tsx +44 -371
- package/src/components/header/variants/LargeTitleHeader/parts/LargeTitleContent.tsx +88 -0
- package/src/components/header/variants/TitleHeader/index.tsx +32 -149
- package/src/components/surface/Surface.tsx +2 -1
|
@@ -10,7 +10,7 @@ export interface LargeTitleHeaderProps extends TitleHeaderProps {
|
|
|
10
10
|
/**
|
|
11
11
|
* How `accessory` moves while scrolling. `'sticky'` starts below the large title
|
|
12
12
|
* and pins below the compact bar when scrolled up. A hidden large title always pins.
|
|
13
|
-
* @defaultValue '
|
|
13
|
+
* @defaultValue 'sticky'
|
|
14
14
|
*/
|
|
15
15
|
accessoryBehavior?: HeaderAccessoryBehavior;
|
|
16
16
|
/**
|
|
@@ -19,26 +19,6 @@ export interface LargeTitleHeaderProps extends TitleHeaderProps {
|
|
|
19
19
|
*/
|
|
20
20
|
titleAlignment?: "center" | "left";
|
|
21
21
|
}
|
|
22
|
-
/**
|
|
23
|
-
|
|
24
|
-
* `Screen`'s portal) into the top of the scroll content, so it scrolls away
|
|
25
|
-
* naturally; the compact title cross-fades over the theme header height.
|
|
26
|
-
* The top safe area and bar overlay fade from transparent when expanded to
|
|
27
|
-
* the header background when collapsed. The large-title content stays transparent.
|
|
28
|
-
* Snapping is opt-in through the scroll container's snapToOffsets.
|
|
29
|
-
*
|
|
30
|
-
* Must be used inside a `Screen` with a `Screen.ScrollView` or `Screen.List`.
|
|
31
|
-
*
|
|
32
|
-
* @example
|
|
33
|
-
* ```tsx
|
|
34
|
-
* <Screen.Header>
|
|
35
|
-
* <Header.LargeTitle
|
|
36
|
-
* overline="Today"
|
|
37
|
-
* title="Meditate"
|
|
38
|
-
* subtitle="Good morning"
|
|
39
|
-
* />
|
|
40
|
-
* </Screen.Header>
|
|
41
|
-
* ```
|
|
42
|
-
*/
|
|
43
|
-
export declare function LargeTitleHeader({ title, overline, subtitle, leadingActions, trailingActions, LeftToolbar, RightToolbar, accessory, accessoryPadding, accessoryBehavior, dismissAction, navigation, onDismiss, titleAlignment, isLargeTitleHidden, background, bg, }: LargeTitleHeaderProps): import("react").JSX.Element;
|
|
22
|
+
/** Collapsing header. The expanded title lives in scroll content; the bar and accessory overlay it. */
|
|
23
|
+
export declare function LargeTitleHeader({ title, overline, subtitle, leadingActions, trailingActions, LeftToolbar, RightToolbar, accessory, accessoryPadding, accessoryBehavior, titleAlignment, isLargeTitleHidden, background, bg, ...dismissProps }: LargeTitleHeaderProps): import("react").JSX.Element;
|
|
44
24
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/components/header/variants/LargeTitleHeader/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/components/header/variants/LargeTitleHeader/index.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gBAAa,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAgB,CAAC;AAGvD,MAAM,WAAW,qBAAsB,SAAQ,gBAAgB;IAC7D,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,uBAAuB,CAAC;IAC5C;;;OAGG;IACH,cAAc,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CACpC;AAED,uGAAuG;AACvG,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,eAAe,EACf,WAAW,EACX,YAAY,EACZ,SAAS,EACT,gBAAsB,EACtB,iBAA4B,EAC5B,cAAyB,EACzB,kBAA0B,EAC1B,UAAU,EACV,EAAE,EACF,GAAG,YAAY,EAChB,EAAE,qBAAqB,+BA8CvB"}
|
package/lib/typescript/src/components/header/variants/LargeTitleHeader/parts/LargeTitleContent.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ComponentProps } from "react";
|
|
2
|
+
import Animated from "react-native-reanimated";
|
|
3
|
+
import type { LargeTitleHeaderProps } from "../index.js";
|
|
4
|
+
export declare function LargeTitleContent({ title, overline, subtitle, hasAccessoryBelow, onHeightChange, animatedStyle, }: Pick<LargeTitleHeaderProps, "title" | "overline" | "subtitle"> & {
|
|
5
|
+
/** Reserve a gap before a sticky accessory below this block. */
|
|
6
|
+
hasAccessoryBelow: boolean;
|
|
7
|
+
/** Reports the large-title block's layout height in dp. */
|
|
8
|
+
onHeightChange?: (height: number) => void;
|
|
9
|
+
animatedStyle: ComponentProps<typeof Animated.View>["style"];
|
|
10
|
+
}): import("react").JSX.Element;
|
|
11
|
+
//# sourceMappingURL=LargeTitleContent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LargeTitleContent.d.ts","sourceRoot":"","sources":["../../../../../../../../src/components/header/variants/LargeTitleHeader/parts/LargeTitleContent.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,OAAO,QAAQ,MAAM,yBAAyB,CAAC;AAK/C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAI,CAAC;AAEhD,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,iBAAiB,EACjB,cAAc,EACd,aAAa,GACd,EAAE,IAAI,CAAC,qBAAqB,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,CAAC,GAAG;IAClE,gEAAgE;IAChE,iBAAiB,EAAE,OAAO,CAAC;IAC3B,2DAA2D;IAC3D,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,aAAa,EAAE,cAAc,CAAC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;CAC9D,+BAmCA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
2
|
import type { ColorToken } from "../../../../theme/types";
|
|
3
|
-
import {
|
|
3
|
+
import type { HeaderDismissProps } from "../../header-buttons.js";
|
|
4
4
|
import type { HeaderAccessoryPadding } from "../../types.js";
|
|
5
5
|
export interface TitleHeaderProps extends HeaderDismissProps {
|
|
6
6
|
/**
|
|
@@ -42,22 +42,6 @@ export interface TitleHeaderProps extends HeaderDismissProps {
|
|
|
42
42
|
/** @deprecated Use background. */
|
|
43
43
|
bg?: ColorToken;
|
|
44
44
|
}
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
* inset outside Screen. Within Screen, the root owns safe-area clearance. The inline counterpart to `Header.LargeTitle`; use it for screens that
|
|
48
|
-
* don't need a collapsing large title.
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* ```tsx
|
|
52
|
-
* <Screen.Header>
|
|
53
|
-
* <Header.Title
|
|
54
|
-
* title="Stats"
|
|
55
|
-
* trailingActions={
|
|
56
|
-
* <Toolbar.Button icon="add" accessibilityLabel="Add" onPress={add} />
|
|
57
|
-
* }
|
|
58
|
-
* />
|
|
59
|
-
* </Screen.Header>
|
|
60
|
-
* ```
|
|
61
|
-
*/
|
|
62
|
-
export declare function TitleHeader({ title, leadingActions, trailingActions, LeftToolbar, RightToolbar, accessory, accessoryPadding, dismissAction, navigation, onDismiss, titleAlignment, background, bg, }: TitleHeaderProps): import("react").JSX.Element;
|
|
45
|
+
/** Compact header. Screen owns the safe area when present; standalone headers reserve it here. */
|
|
46
|
+
export declare function TitleHeader({ title, leadingActions, trailingActions, LeftToolbar, RightToolbar, accessory, accessoryPadding, titleAlignment, background, bg, ...dismissProps }: TitleHeaderProps): import("react").JSX.Element;
|
|
63
47
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/components/header/variants/TitleHeader/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/components/header/variants/TitleHeader/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAc,MAAM,OAAO,CAAC;AAKnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAsB,CAAC;AAI/D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAa,CAAC;AAE1D,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB;IAC1D;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;OAGG;IACH,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,sCAAsC;IACtC,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB;;;OAGG;IACH,eAAe,CAAC,EAAE,SAAS,CAAC;IAC5B,uCAAuC;IACvC,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;IAC1C,8DAA8D;IAC9D,cAAc,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IACnC,mGAAmG;IACnG,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,kCAAkC;IAClC,EAAE,CAAC,EAAE,UAAU,CAAC;CACjB;AAED,kGAAkG;AAClG,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,cAAc,EACd,eAAe,EACf,WAAW,EACX,YAAY,EACZ,SAAS,EACT,gBAAsB,EACtB,cAAyB,EACzB,UAAU,EACV,EAAE,EACF,GAAG,YAAY,EAChB,EAAE,gBAAgB,+BA0BlB"}
|
|
@@ -34,5 +34,5 @@ export interface SurfaceProps extends Omit<BoxProps, "background"> {
|
|
|
34
34
|
* </Surface>
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
|
-
export declare const Surface: import("react").ForwardRefExoticComponent<SurfaceProps & import("react").RefAttributes<import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default>>;
|
|
37
|
+
export declare const Surface: import("react").ForwardRefExoticComponent<Omit<SurfaceProps, "ref"> & import("react").RefAttributes<import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default>>;
|
|
38
38
|
//# sourceMappingURL=Surface.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Surface.d.ts","sourceRoot":"","sources":["../../../../../src/components/surface/Surface.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAc,YAAY,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAA8B,KAAK,QAAQ,EAAE,MAAM,iBAAQ,CAAC;AAEnE,6CAA6C;AAC7C,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,aAAa,CAAC;AAE1E,MAAM,WAAW,YAAa,SAAQ,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChE,sDAAsD;IACtD,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,YAAY,CAAC;CAC1B;AA6BD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"Surface.d.ts","sourceRoot":"","sources":["../../../../../src/components/surface/Surface.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAc,YAAY,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAA8B,KAAK,QAAQ,EAAE,MAAM,iBAAQ,CAAC;AAEnE,6CAA6C;AAC7C,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,aAAa,CAAC;AAE1E,MAAM,WAAW,YAAa,SAAQ,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChE,sDAAsD;IACtD,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,YAAY,CAAC;CAC1B;AA6BD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,OAAO,uMAkBlB,CAAC"}
|
|
@@ -22,7 +22,7 @@ export interface ToastProps extends Omit<SurfaceProps, "id" | "variant"> {
|
|
|
22
22
|
/** Local close callback used by `Toast.Close`. */
|
|
23
23
|
onClose?: () => void;
|
|
24
24
|
}
|
|
25
|
-
declare const ToastRoot: import("react").ForwardRefExoticComponent<ToastProps & import("react").RefAttributes<import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default>>;
|
|
25
|
+
declare const ToastRoot: import("react").ForwardRefExoticComponent<Omit<ToastProps, "ref"> & import("react").RefAttributes<import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default>>;
|
|
26
26
|
export interface ToastTitleProps extends TextProps {
|
|
27
27
|
}
|
|
28
28
|
declare const ToastTitle: import("react").ForwardRefExoticComponent<ToastTitleProps & import("react").RefAttributes<import("react-native/types_generated/src/private/webapis/dom/nodes/ReactNativeElement").default>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toast.d.ts","sourceRoot":"","sources":["../../../../../src/components/toast/Toast.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EAIf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAyB,cAAc,EAAQ,MAAM,cAAc,CAAC;AAKhF,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,cAAc,CAAC;AAE9D,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,oBAAW,CAAC;AACrD,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,kBAAS,CAAC;AAC/C,OAAO,EAAW,KAAK,YAAY,EAAE,MAAM,qBAAY,CAAC;AACxD,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,kBAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,OAAO,IAAI,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAS,CAAC;AAGzE,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE5F,KAAK,eAAe,GAAG,MAAM,GAAG,MAAM,CAAC;AAEvC,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,eAAe,KAAK,IAAI,CAAC;IACrC,EAAE,CAAC,EAAE,eAAe,CAAC;CACtB;AAoED,MAAM,WAAW,UAAW,SAAQ,IAAI,CAAC,YAAY,EAAE,IAAI,GAAG,SAAS,CAAC;IACtE,wDAAwD;IACxD,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,+EAA+E;IAC/E,EAAE,CAAC,EAAE,eAAe,CAAC;IACrB,+DAA+D;IAC/D,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,eAAe,KAAK,IAAI,CAAC;IACrC,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"Toast.d.ts","sourceRoot":"","sources":["../../../../../src/components/toast/Toast.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,53 +1,96 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
type ComponentPropsWithRef,
|
|
3
|
+
type ElementType,
|
|
4
|
+
forwardRef,
|
|
5
|
+
type ReactElement,
|
|
6
|
+
type ReactNode,
|
|
7
|
+
} from "react";
|
|
8
|
+
import { type StyleProp, View, type ViewStyle } from "react-native";
|
|
3
9
|
|
|
4
10
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
|
5
11
|
|
|
6
12
|
import { Slot } from "../slot";
|
|
7
13
|
import { BOX_STYLE_PROP_KEYS, type BoxStyleProps, resolveBoxStyle } from "./utils";
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
|
|
15
|
+
/** Props owned by Box itself — everything else belongs to the rendered element. */
|
|
16
|
+
interface BoxOwnProps extends BoxStyleProps {
|
|
17
|
+
/** Merge Box's style/props onto a single child instead of rendering an element. Takes precedence over `as`. */
|
|
11
18
|
asChild?: boolean;
|
|
12
19
|
}
|
|
13
20
|
|
|
14
|
-
const STYLE_KEYS = new Set<string>(BOX_STYLE_PROP_KEYS as readonly string[]);
|
|
15
|
-
|
|
16
21
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
22
|
+
* Props of `Box` when cast as `T`. Token style-props plus everything the
|
|
23
|
+
* rendered component accepts — `<Box as={Pressable} onPress={…} />` type-checks
|
|
24
|
+
* against `Pressable`, not `View`.
|
|
19
25
|
*/
|
|
20
|
-
export
|
|
21
|
-
|
|
26
|
+
export type BoxProps<T extends ElementType = typeof View> = BoxOwnProps & {
|
|
27
|
+
/** Render as this component instead of `View`. It must accept a `style` prop. */
|
|
28
|
+
as?: T;
|
|
29
|
+
} & Omit<ComponentPropsWithRef<T>, keyof BoxOwnProps | "as">;
|
|
30
|
+
|
|
31
|
+
/** Erased prop shape the implementation works with — the generic lives on the exported cast. */
|
|
32
|
+
interface BoxRenderProps extends BoxOwnProps {
|
|
33
|
+
as?: ElementType;
|
|
34
|
+
style?: StyleProp<ViewStyle>;
|
|
35
|
+
children?: ReactNode;
|
|
36
|
+
[key: string]: unknown;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const STYLE_KEYS = new Set<string>(BOX_STYLE_PROP_KEYS as readonly string[]);
|
|
40
|
+
|
|
41
|
+
const BoxWithRef = forwardRef<unknown, BoxRenderProps>(function Box(
|
|
42
|
+
{ as, asChild, style, children, ...rest }: BoxRenderProps,
|
|
22
43
|
ref
|
|
23
44
|
) {
|
|
24
45
|
const { theme } = useUnistyles();
|
|
25
46
|
|
|
26
47
|
const styleProps: Record<string, unknown> = {};
|
|
27
|
-
const
|
|
48
|
+
const elementProps: Record<string, unknown> = {};
|
|
28
49
|
for (const key of Object.keys(rest)) {
|
|
29
|
-
const value =
|
|
50
|
+
const value = rest[key];
|
|
30
51
|
if (STYLE_KEYS.has(key)) styleProps[key] = value;
|
|
31
|
-
else
|
|
52
|
+
else elementProps[key] = value;
|
|
32
53
|
}
|
|
33
54
|
|
|
34
55
|
const mergedStyle = [styles.root, resolveBoxStyle(styleProps as BoxStyleProps, theme), style];
|
|
35
56
|
|
|
36
57
|
if (asChild) {
|
|
37
58
|
return (
|
|
38
|
-
<Slot ownerName="Box" slotProps={{ ...
|
|
59
|
+
<Slot ownerName="Box" slotProps={{ ...elementProps, style: mergedStyle, ref }}>
|
|
39
60
|
{children}
|
|
40
61
|
</Slot>
|
|
41
62
|
);
|
|
42
63
|
}
|
|
43
64
|
|
|
65
|
+
const Component = (as ?? View) as ElementType;
|
|
66
|
+
|
|
44
67
|
return (
|
|
45
|
-
<
|
|
68
|
+
<Component ref={ref} style={mergedStyle} {...elementProps}>
|
|
46
69
|
{children}
|
|
47
|
-
</
|
|
70
|
+
</Component>
|
|
48
71
|
);
|
|
49
72
|
});
|
|
50
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Base layout primitive: a `View` styled through theme-token props.
|
|
76
|
+
* The only component family exposing token style-props.
|
|
77
|
+
*
|
|
78
|
+
* Pass `as` to cast it as another component — the token style-props still
|
|
79
|
+
* resolve, and the rest of the props are typed against that component.
|
|
80
|
+
* Note that `as` renders a component Box does not own, so a Unistyles style
|
|
81
|
+
* handed to it only stays theme-reactive if that component's own module runs
|
|
82
|
+
* through the Unistyles Babel plugin (see the stylesheet note below).
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```tsx
|
|
86
|
+
* <Box row gap="2" p="4" />
|
|
87
|
+
* <Box as={Pressable} onPress={onPress} p="3" radius="md" />
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export const Box = BoxWithRef as unknown as <T extends ElementType = typeof View>(
|
|
91
|
+
props: BoxProps<T>
|
|
92
|
+
) => ReactElement | null;
|
|
93
|
+
|
|
51
94
|
// ─── Styles ───────────────────────────────────────────────────────────────────
|
|
52
95
|
//
|
|
53
96
|
// Box has no static style of its own — this stylesheet exists so the
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
|
|
3
|
+
import { useUnistyles } from "react-native-unistyles";
|
|
4
|
+
|
|
5
|
+
import type { ColorToken } from "#theme/types";
|
|
6
|
+
import { resolveThemeColor } from "#utils/resolve-theme-color";
|
|
7
|
+
import { ScreenContext } from "../../screen/ScreenContext";
|
|
8
|
+
|
|
9
|
+
/** Explicit header color wins, then Screen, then the theme canvas. */
|
|
10
|
+
export function useHeaderColor(token?: ColorToken) {
|
|
11
|
+
const { theme } = useUnistyles();
|
|
12
|
+
const screen = useContext(ScreenContext);
|
|
13
|
+
return (token ? resolveThemeColor(token, theme) : screen?.background) ?? theme.color["surface.canvas"];
|
|
14
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useEffect, useLayoutEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { interpolate, useAnimatedStyle, useSharedValue } from "react-native-reanimated";
|
|
4
|
+
import { useUnistyles } from "react-native-unistyles";
|
|
5
|
+
|
|
6
|
+
import { useScreen } from "../../screen/ScreenContext";
|
|
7
|
+
import type { HeaderAccessoryBehavior } from "../types";
|
|
8
|
+
|
|
9
|
+
interface LargeTitleLayoutOptions {
|
|
10
|
+
hasAccessory: boolean;
|
|
11
|
+
accessoryBehavior: HeaderAccessoryBehavior;
|
|
12
|
+
isLargeTitleHidden: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Coordinates measured layout and UI-thread animation without animating accessory padding. */
|
|
16
|
+
export function useLargeTitleHeader({
|
|
17
|
+
hasAccessory,
|
|
18
|
+
accessoryBehavior,
|
|
19
|
+
isLargeTitleHidden,
|
|
20
|
+
}: LargeTitleLayoutOptions) {
|
|
21
|
+
const { theme } = useUnistyles();
|
|
22
|
+
const { scrollY, contentTopPadding, setHeaderAccessoryHeight } = useScreen();
|
|
23
|
+
const [accessoryHeight, setAccessoryHeight] = useState(0);
|
|
24
|
+
const [largeTitleHeight, setLargeTitleHeight] = useState(0);
|
|
25
|
+
const hidden = useSharedValue(isLargeTitleHidden);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
hidden.value = isLargeTitleHidden;
|
|
28
|
+
}, [hidden, isLargeTitleHidden]);
|
|
29
|
+
|
|
30
|
+
const barHeight = theme.layout.header.height;
|
|
31
|
+
const isSticky = hasAccessory && accessoryBehavior === "sticky" && !isLargeTitleHidden;
|
|
32
|
+
// The measured overlay always includes bottom padding. Expanded scroll content
|
|
33
|
+
// excludes it; compact-only screens reserve the entire accessory.
|
|
34
|
+
const reservedAccessoryHeight = hasAccessory
|
|
35
|
+
? Math.max(0, Math.round(accessoryHeight - (isLargeTitleHidden ? 0 : theme.spacing["2"])))
|
|
36
|
+
: 0;
|
|
37
|
+
const accessoryOffset = isSticky ? Math.max(0, contentTopPadding + largeTitleHeight - barHeight) : 0;
|
|
38
|
+
|
|
39
|
+
useLayoutEffect(() => {
|
|
40
|
+
setHeaderAccessoryHeight(isSticky ? 0 : reservedAccessoryHeight);
|
|
41
|
+
return () => setHeaderAccessoryHeight(0);
|
|
42
|
+
}, [isSticky, reservedAccessoryHeight, setHeaderAccessoryHeight]);
|
|
43
|
+
|
|
44
|
+
const accessoryStyle = useAnimatedStyle(() => ({
|
|
45
|
+
transform: [{ translateY: isSticky && !hidden.value ? Math.max(0, accessoryOffset - scrollY.value) : 0 }],
|
|
46
|
+
}));
|
|
47
|
+
const surfaceStyle = useAnimatedStyle(() => {
|
|
48
|
+
if (hidden.value) return { opacity: 1 };
|
|
49
|
+
const distance = isSticky ? accessoryOffset : barHeight;
|
|
50
|
+
return {
|
|
51
|
+
opacity: distance > 0 ? interpolate(scrollY.value, [0, distance], [0, 1], "clamp") : isSticky ? 1 : 0,
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
const compactTitleStyle = useAnimatedStyle(() => {
|
|
55
|
+
const progress = hidden.value
|
|
56
|
+
? 1
|
|
57
|
+
: barHeight > 0
|
|
58
|
+
? interpolate(scrollY.value, [0, barHeight], [0, 1], "clamp")
|
|
59
|
+
: 0;
|
|
60
|
+
return { opacity: progress, transform: [{ translateY: (1 - progress) * 8 }] };
|
|
61
|
+
});
|
|
62
|
+
const largeTitleStyle = useAnimatedStyle(() => {
|
|
63
|
+
const progress = barHeight > 0 ? interpolate(scrollY.value, [0, barHeight], [0, 1], "clamp") : 0;
|
|
64
|
+
return { opacity: 1 - progress, transform: [{ translateY: -progress * 6 }] };
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
isSticky,
|
|
69
|
+
accessoryOffset,
|
|
70
|
+
reservedAccessoryHeight,
|
|
71
|
+
setAccessoryHeight,
|
|
72
|
+
setLargeTitleHeight,
|
|
73
|
+
accessoryStyle,
|
|
74
|
+
surfaceStyle,
|
|
75
|
+
compactTitleStyle,
|
|
76
|
+
largeTitleStyle,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -1,37 +1,53 @@
|
|
|
1
|
-
import { type ReactNode, useCallback,
|
|
2
|
-
import { type LayoutChangeEvent,
|
|
1
|
+
import { type ComponentProps, type ReactNode, useCallback, useLayoutEffect, useRef } from "react";
|
|
2
|
+
import { type LayoutChangeEvent, View } from "react-native";
|
|
3
3
|
|
|
4
4
|
import Animated from "react-native-reanimated";
|
|
5
5
|
import { StyleSheet } from "react-native-unistyles";
|
|
6
6
|
|
|
7
7
|
import type { HeaderAccessoryPadding } from "../types";
|
|
8
|
+
import { HeaderSurface, type HeaderSurfaceProps } from "./HeaderSurface";
|
|
8
9
|
|
|
9
10
|
export interface HeaderAccessoryProps {
|
|
10
11
|
children: ReactNode;
|
|
11
12
|
/** Horizontal padding around the accessory. */
|
|
12
13
|
padding: HeaderAccessoryPadding;
|
|
14
|
+
color: string;
|
|
15
|
+
surfaceStyle?: HeaderSurfaceProps["animatedStyle"];
|
|
13
16
|
/** Reports layout height in dp; reports zero on cleanup to release reserved space. */
|
|
14
|
-
onHeightChange
|
|
17
|
+
onHeightChange?: (height: number) => void;
|
|
15
18
|
/** Additional styles for the accessory container. */
|
|
16
|
-
style?:
|
|
19
|
+
style?: ComponentProps<typeof Animated.View>["style"];
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
/** Measures accessory content so the header can reserve space in the scroll container. */
|
|
20
|
-
export function HeaderAccessory({
|
|
23
|
+
export function HeaderAccessory({
|
|
24
|
+
children,
|
|
25
|
+
padding,
|
|
26
|
+
color,
|
|
27
|
+
surfaceStyle,
|
|
28
|
+
onHeightChange,
|
|
29
|
+
style,
|
|
30
|
+
}: HeaderAccessoryProps) {
|
|
31
|
+
const measuredHeight = useRef(0);
|
|
21
32
|
const handleLayout = useCallback(
|
|
22
33
|
(event: LayoutChangeEvent) => {
|
|
23
|
-
|
|
34
|
+
measuredHeight.current = event.nativeEvent.layout.height;
|
|
35
|
+
onHeightChange?.(measuredHeight.current);
|
|
24
36
|
},
|
|
25
37
|
[onHeightChange]
|
|
26
38
|
);
|
|
27
39
|
|
|
28
40
|
// Release the previous owner’s space when the callback changes or the accessory unmounts.
|
|
29
|
-
|
|
41
|
+
useLayoutEffect(() => {
|
|
42
|
+
onHeightChange?.(measuredHeight.current);
|
|
43
|
+
return () => onHeightChange?.(0);
|
|
44
|
+
}, [onHeightChange]);
|
|
30
45
|
|
|
31
46
|
styles.useVariants({ padding });
|
|
32
47
|
|
|
33
48
|
return (
|
|
34
49
|
<Animated.View style={[styles.accessory, style]} onLayout={handleLayout}>
|
|
50
|
+
<HeaderSurface color={color} animatedStyle={surfaceStyle} accessory />
|
|
35
51
|
{children}
|
|
36
52
|
</Animated.View>
|
|
37
53
|
);
|
|
@@ -44,6 +60,9 @@ export function HeaderAccessorySpacer({ height }: { height: number }) {
|
|
|
44
60
|
|
|
45
61
|
const styles = StyleSheet.create((theme) => ({
|
|
46
62
|
accessory: {
|
|
63
|
+
// Static layout padding is intentional: the background must measure the full
|
|
64
|
+
// padded height even when a horizontal ScrollView is the accessory content.
|
|
65
|
+
paddingBottom: theme.spacing["2"],
|
|
47
66
|
variants: {
|
|
48
67
|
padding: {
|
|
49
68
|
x: { paddingHorizontal: theme.layout.screen.padding.x },
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { ComponentProps, ReactNode } from "react";
|
|
2
|
+
import { Text, View } from "react-native";
|
|
3
|
+
|
|
4
|
+
import Animated from "react-native-reanimated";
|
|
5
|
+
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
|
6
|
+
|
|
7
|
+
import { FONT_WEIGHT_VALUE } from "#utils/typography";
|
|
8
|
+
import { Toolbar } from "../../toolbar";
|
|
9
|
+
import { HeaderDismissButton, type HeaderDismissProps } from "../header-buttons";
|
|
10
|
+
import { isCustomTitle, isTextTitle } from "../utils";
|
|
11
|
+
import { HeaderSurface, type HeaderSurfaceProps } from "./HeaderSurface";
|
|
12
|
+
|
|
13
|
+
interface HeaderBarProps extends HeaderDismissProps {
|
|
14
|
+
title?: ReactNode;
|
|
15
|
+
leading?: ReactNode;
|
|
16
|
+
trailing?: ReactNode;
|
|
17
|
+
titleAlignment: "center" | "left";
|
|
18
|
+
color: string;
|
|
19
|
+
surfaceStyle?: HeaderSurfaceProps["animatedStyle"];
|
|
20
|
+
titleStyle?: ComponentProps<typeof Animated.View>["style"];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Shared compact bar. Only the title and background animate; actions stay interactive. */
|
|
24
|
+
export function HeaderBar({
|
|
25
|
+
title,
|
|
26
|
+
leading,
|
|
27
|
+
trailing,
|
|
28
|
+
titleAlignment,
|
|
29
|
+
color,
|
|
30
|
+
surfaceStyle,
|
|
31
|
+
titleStyle,
|
|
32
|
+
dismissAction = "none",
|
|
33
|
+
navigation,
|
|
34
|
+
onDismiss,
|
|
35
|
+
}: HeaderBarProps) {
|
|
36
|
+
const { theme } = useUnistyles();
|
|
37
|
+
styles.useVariants({ titleAlignment });
|
|
38
|
+
const dismiss = (
|
|
39
|
+
<HeaderDismissButton dismissAction={dismissAction} navigation={navigation} onDismiss={onDismiss} />
|
|
40
|
+
);
|
|
41
|
+
return (
|
|
42
|
+
<View style={styles.bar}>
|
|
43
|
+
<HeaderSurface color={color} animatedStyle={surfaceStyle} />
|
|
44
|
+
{(leading != null || dismissAction === "back") && (
|
|
45
|
+
<Toolbar>
|
|
46
|
+
{dismissAction === "back" && dismiss}
|
|
47
|
+
{leading}
|
|
48
|
+
</Toolbar>
|
|
49
|
+
)}
|
|
50
|
+
<Animated.View
|
|
51
|
+
style={[styles.titleContainer, titleStyle]}
|
|
52
|
+
pointerEvents={isCustomTitle(title) ? "box-none" : "none"}
|
|
53
|
+
>
|
|
54
|
+
{isTextTitle(title)
|
|
55
|
+
? String(title).trim().length > 0 && (
|
|
56
|
+
<Text
|
|
57
|
+
style={styles.title}
|
|
58
|
+
maxFontSizeMultiplier={theme.typography.variants["title-md"].maxFontSizeMultiplier}
|
|
59
|
+
>
|
|
60
|
+
{title}
|
|
61
|
+
</Text>
|
|
62
|
+
)
|
|
63
|
+
: title}
|
|
64
|
+
</Animated.View>
|
|
65
|
+
{(trailing != null || dismissAction === "close") && (
|
|
66
|
+
<Toolbar style={styles.trailing}>
|
|
67
|
+
{dismissAction === "close" && dismiss}
|
|
68
|
+
{trailing}
|
|
69
|
+
</Toolbar>
|
|
70
|
+
)}
|
|
71
|
+
</View>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const styles = StyleSheet.create((theme) => ({
|
|
76
|
+
bar: {
|
|
77
|
+
height: theme.layout.header.height,
|
|
78
|
+
flexDirection: "row",
|
|
79
|
+
alignItems: "center",
|
|
80
|
+
paddingHorizontal: theme.layout.screen.padding.x,
|
|
81
|
+
gap: theme.spacing["3"],
|
|
82
|
+
justifyContent: "space-between",
|
|
83
|
+
},
|
|
84
|
+
// A centered title is absolutely positioned, so it leaves the flex row. With
|
|
85
|
+
// no leading slot the trailing toolbar would be the only in-flow child and
|
|
86
|
+
// `space-between` would park it on the left — the auto margin pins it right.
|
|
87
|
+
trailing: {
|
|
88
|
+
justifyContent: "flex-end",
|
|
89
|
+
variants: {
|
|
90
|
+
titleAlignment: {
|
|
91
|
+
center: { marginLeft: "auto" },
|
|
92
|
+
left: {},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
titleContainer: {
|
|
97
|
+
variants: {
|
|
98
|
+
titleAlignment: {
|
|
99
|
+
center: {
|
|
100
|
+
position: "absolute",
|
|
101
|
+
left: 0,
|
|
102
|
+
right: 0,
|
|
103
|
+
alignItems: "center",
|
|
104
|
+
},
|
|
105
|
+
left: {
|
|
106
|
+
flex: 1,
|
|
107
|
+
alignItems: "flex-start",
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
title: {
|
|
113
|
+
fontSize: theme.typography.variants["title-md"].fontSize,
|
|
114
|
+
lineHeight: theme.typography.variants["title-md"].lineHeight,
|
|
115
|
+
letterSpacing: theme.typography.variants["title-md"].letterSpacing,
|
|
116
|
+
fontWeight: FONT_WEIGHT_VALUE[theme.typography.variants["title-md"].fontWeight],
|
|
117
|
+
color: (theme.color as unknown as Record<string, string | undefined>)["text.primary"] ?? "",
|
|
118
|
+
variants: {
|
|
119
|
+
titleAlignment: {
|
|
120
|
+
center: { textAlign: "center" },
|
|
121
|
+
left: { textAlign: "left" },
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
}));
|