react-native-terra-ui 0.11.5 → 0.11.7

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 (54) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/lib/module/components/chip/Chip.js +25 -8
  3. package/lib/module/components/chip/Chip.js.map +1 -1
  4. package/lib/module/components/chip/utils.js +1 -1
  5. package/lib/module/components/chip/utils.js.map +1 -1
  6. package/lib/module/components/header/index.js.map +1 -1
  7. package/lib/module/components/header/parts/HeaderAccessory.js +58 -0
  8. package/lib/module/components/header/parts/HeaderAccessory.js.map +1 -0
  9. package/lib/module/components/header/parts/HeaderSurface.js +58 -0
  10. package/lib/module/components/header/parts/HeaderSurface.js.map +1 -0
  11. package/lib/module/components/header/types.js +2 -0
  12. package/lib/module/components/header/types.js.map +1 -0
  13. package/lib/module/components/header/variants/LargeTitleHeader/index.js +114 -46
  14. package/lib/module/components/header/variants/LargeTitleHeader/index.js.map +1 -1
  15. package/lib/module/components/header/variants/TitleHeader/index.js +33 -28
  16. package/lib/module/components/header/variants/TitleHeader/index.js.map +1 -1
  17. package/lib/module/components/screen/ScreenContext.js +16 -1
  18. package/lib/module/components/screen/ScreenContext.js.map +1 -1
  19. package/lib/module/components/screen/ScreenList.js +24 -5
  20. package/lib/module/components/screen/ScreenList.js.map +1 -1
  21. package/lib/module/components/screen/ScreenScrollView.js +10 -4
  22. package/lib/module/components/screen/ScreenScrollView.js.map +1 -1
  23. package/lib/typescript/src/components/chip/Chip.d.ts +8 -0
  24. package/lib/typescript/src/components/chip/Chip.d.ts.map +1 -1
  25. package/lib/typescript/src/components/chip/utils.d.ts +6 -1
  26. package/lib/typescript/src/components/chip/utils.d.ts.map +1 -1
  27. package/lib/typescript/src/components/header/index.d.ts +1 -0
  28. package/lib/typescript/src/components/header/index.d.ts.map +1 -1
  29. package/lib/typescript/src/components/header/parts/HeaderAccessory.d.ts +19 -0
  30. package/lib/typescript/src/components/header/parts/HeaderAccessory.d.ts.map +1 -0
  31. package/lib/typescript/src/components/header/parts/HeaderSurface.d.ts +22 -0
  32. package/lib/typescript/src/components/header/parts/HeaderSurface.d.ts.map +1 -0
  33. package/lib/typescript/src/components/header/types.d.ts +15 -0
  34. package/lib/typescript/src/components/header/types.d.ts.map +1 -0
  35. package/lib/typescript/src/components/header/variants/LargeTitleHeader/index.d.ts +8 -1
  36. package/lib/typescript/src/components/header/variants/LargeTitleHeader/index.d.ts.map +1 -1
  37. package/lib/typescript/src/components/header/variants/TitleHeader/index.d.ts +14 -1
  38. package/lib/typescript/src/components/header/variants/TitleHeader/index.d.ts.map +1 -1
  39. package/lib/typescript/src/components/screen/ScreenContext.d.ts +22 -0
  40. package/lib/typescript/src/components/screen/ScreenContext.d.ts.map +1 -1
  41. package/lib/typescript/src/components/screen/ScreenList.d.ts.map +1 -1
  42. package/lib/typescript/src/components/screen/ScreenScrollView.d.ts.map +1 -1
  43. package/package.json +1 -1
  44. package/src/components/chip/Chip.tsx +22 -9
  45. package/src/components/chip/utils.ts +7 -2
  46. package/src/components/header/index.ts +1 -0
  47. package/src/components/header/parts/HeaderAccessory.tsx +55 -0
  48. package/src/components/header/parts/HeaderSurface.tsx +62 -0
  49. package/src/components/header/types.ts +15 -0
  50. package/src/components/header/variants/LargeTitleHeader/index.tsx +114 -42
  51. package/src/components/header/variants/TitleHeader/index.tsx +45 -22
  52. package/src/components/screen/ScreenContext.tsx +42 -0
  53. package/src/components/screen/ScreenList.tsx +30 -5
  54. package/src/components/screen/ScreenScrollView.tsx +28 -6
@@ -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,EAAc,MAAM,OAAO,CAAC;AAKnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM/C,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,yBAAsB,CAAC;AAIpF,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,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;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,cAAc,EACd,eAAe,EACf,WAAW,EACX,YAAY,EACZ,aAAsB,EACtB,UAAU,EACV,SAAS,EACT,cAAyB,EACzB,UAAU,EACV,EAAE,GACH,EAAE,gBAAgB,+BAoDlB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/components/header/variants/TitleHeader/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAA2B,MAAM,OAAO,CAAC;AAKhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM/C,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,yBAAsB,CAAC;AAGpF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAa,CAAC;AAG1D,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;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,cAAc,EACd,eAAe,EACf,WAAW,EACX,YAAY,EACZ,SAAS,EACT,gBAAsB,EACtB,aAAsB,EACtB,UAAU,EACV,SAAS,EACT,cAAyB,EACzB,UAAU,EACV,EAAE,GACH,EAAE,gBAAgB,+BAiElB"}
@@ -51,6 +51,28 @@ export interface ScreenContextValue {
51
51
  margins: ScreenContentPadding;
52
52
  /** Whether a `Screen.Header` is present. Used by scroll containers to add top inset. */
53
53
  hasHeader: boolean;
54
+ /**
55
+ * Measured height (dp) of the pinned accessory a header renders below its bar
56
+ * — a search field, a tab strip. Zero when there is none.
57
+ *
58
+ * The theme header height covers the bar alone, and an accessory is whatever
59
+ * the caller put there, so scroll containers reserve this on top of it. That
60
+ * is why it is measured rather than declared: only the accessory knows how
61
+ * tall it is, and it can change with Dynamic Type or its own content.
62
+ */
63
+ headerAccessoryHeight: number;
64
+ /**
65
+ * Reports the measured accessory height. Called by the header that owns the
66
+ * accessory; zero releases the reserved space.
67
+ */
68
+ setHeaderAccessoryHeight: (height: number) => void;
69
+ /**
70
+ * Primary scroll container's resolved top padding in dp, including header clearance.
71
+ * Used to position a sticky accessory below the large title at scroll offset zero.
72
+ */
73
+ contentTopPadding: number;
74
+ /** Reported by the primary scroll container from its layout or resolved padding. */
75
+ setContentTopPadding: (padding: number) => void;
54
76
  /** Vertical scroll offset, updated on the UI thread for header animations. */
55
77
  scrollY: SharedValue<number>;
56
78
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ScreenContext.d.ts","sourceRoot":"","sources":["../../../../../src/components/screen/ScreenContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAA8C,MAAM,OAAO,CAAC;AAElG,OAAO,QAAQ,EAAE,EACf,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAC3B,KAAK,WAAW,EAIjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,YAAS,CAAC;AAEpE,6EAA6E;AAC7E,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AAE/D,yDAAyD;AACzD,eAAO,MAAM,yBAAyB,kBAAkB,CAAC;AAEzD,gFAAgF;AAChF,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,cAAc,EAAE,oBAAoB,CAAC;IACrC,6EAA6E;IAC7E,QAAQ,EAAE,cAAc,CAAC;IACzB;;;;;;;;;OASG;IACH,sBAAsB,EAAE,OAAO,CAAC;IAChC;;;;;;;;;;OAUG;IACH,qBAAqB,EAAE,OAAO,CAAC;IAC/B;;;;;;;;OAQG;IACH,sBAAsB,EAAE,OAAO,CAAC;IAChC,sCAAsC;IACtC,OAAO,EAAE,oBAAoB,CAAC;IAC9B,wFAAwF;IACxF,SAAS,EAAE,OAAO,CAAC;IACnB,8EAA8E;IAC9E,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7B;;;OAGG;IACH,oBAAoB,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1C;;;OAGG;IACH,iBAAiB,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACxC,iGAAiG;IACjG,uBAAuB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD;;;;OAIG;IACH,SAAS,EAAE,eAAe,CAAC;IAC3B,yDAAyD;IACzD,aAAa,EAAE,sBAAsB,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAE/D,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,aAAa,oDAAiD,CAAC;AAE5E,4DAA4D;AAC5D,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,SAAS,CAAC;IACpB,sFAAsF;IACtF,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,qFAAqF;IACrF,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,0FAA0F;IAC1F,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,6EAA6E;IAC7E,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,iEAAiE;IACjE,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,UAA0B,EAC1B,QAAQ,EACR,cAAsB,EACtB,QAAiB,EACjB,sBAA8B,EAC9B,qBAA6B,EAC7B,sBAA8B,EAC9B,SAAiB,GAClB,EAAE,yBAAyB,+BAwD3B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,IAAI,kBAAkB,CAM9C"}
1
+ {"version":3,"file":"ScreenContext.d.ts","sourceRoot":"","sources":["../../../../../src/components/screen/ScreenContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAA8C,MAAM,OAAO,CAAC;AAElG,OAAO,QAAQ,EAAE,EACf,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAC3B,KAAK,WAAW,EAIjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,YAAS,CAAC;AAEpE,6EAA6E;AAC7E,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AAE/D,yDAAyD;AACzD,eAAO,MAAM,yBAAyB,kBAAkB,CAAC;AAEzD,gFAAgF;AAChF,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,cAAc,EAAE,oBAAoB,CAAC;IACrC,6EAA6E;IAC7E,QAAQ,EAAE,cAAc,CAAC;IACzB;;;;;;;;;OASG;IACH,sBAAsB,EAAE,OAAO,CAAC;IAChC;;;;;;;;;;OAUG;IACH,qBAAqB,EAAE,OAAO,CAAC;IAC/B;;;;;;;;OAQG;IACH,sBAAsB,EAAE,OAAO,CAAC;IAChC,sCAAsC;IACtC,OAAO,EAAE,oBAAoB,CAAC;IAC9B,wFAAwF;IACxF,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;;;;OAQG;IACH,qBAAqB,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,wBAAwB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD;;;OAGG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oFAAoF;IACpF,oBAAoB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,8EAA8E;IAC9E,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7B;;;OAGG;IACH,oBAAoB,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1C;;;OAGG;IACH,iBAAiB,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACxC,iGAAiG;IACjG,uBAAuB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD;;;;OAIG;IACH,SAAS,EAAE,eAAe,CAAC;IAC3B,yDAAyD;IACzD,aAAa,EAAE,sBAAsB,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAE/D,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,aAAa,oDAAiD,CAAC;AAE5E,4DAA4D;AAC5D,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,SAAS,CAAC;IACpB,sFAAsF;IACtF,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,qFAAqF;IACrF,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,0FAA0F;IAC1F,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,6EAA6E;IAC7E,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,iEAAiE;IACjE,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,UAA0B,EAC1B,QAAQ,EACR,cAAsB,EACtB,QAAiB,EACjB,sBAA8B,EAC9B,qBAA6B,EAC7B,sBAA8B,EAC9B,SAAiB,GAClB,EAAE,yBAAyB,+BA4E3B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,IAAI,kBAAkB,CAM9C"}
@@ -1 +1 @@
1
- {"version":3,"file":"ScreenList.d.ts","sourceRoot":"","sources":["../../../../../src/components/screen/ScreenList.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ScreenList.d.ts","sourceRoot":"","sources":["../../../../../src/components/screen/ScreenList.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ScreenScrollView.d.ts","sourceRoot":"","sources":["../../../../../src/components/screen/ScreenScrollView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA2C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAChF,OAAO,EAAmB,KAAK,eAAe,EAAE,KAAK,SAAS,EAAQ,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAa3G,OAAO,KAAK,EAAwB,qBAAqB,EAAE,MAAM,YAAS,CAAC;AAG3E,qFAAqF;AACrF,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,EAAE,qBAAqB;IACvG,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,iEAAiE;IACjE,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,uFAAuF;IACvF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,gBAAgB,8MA6E5B,CAAC"}
1
+ {"version":3,"file":"ScreenScrollView.d.ts","sourceRoot":"","sources":["../../../../../src/components/screen/ScreenScrollView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA2C,KAAK,SAAS,EAAe,MAAM,OAAO,CAAC;AAC7F,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,SAAS,EAEd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAatB,OAAO,KAAK,EAAwB,qBAAqB,EAAE,MAAM,YAAS,CAAC;AAG3E,qFAAqF;AACrF,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,EAAE,qBAAqB;IACvG,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,iEAAiE;IACjE,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpC,uFAAuF;IACvF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,gBAAgB,8MAoF5B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-terra-ui",
3
- "version": "0.11.5",
3
+ "version": "0.11.7",
4
4
  "description": "Themeable React Native UI components built on react-native-unistyles",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -14,6 +14,14 @@ export interface ChipProps extends ViewProps {
14
14
  size?: ChipSize;
15
15
  variant?: ChipVariant;
16
16
  color?: ChipColor;
17
+ /**
18
+ * Fill behind the chip, overriding the one its `variant` would paint.
19
+ *
20
+ * Only `outline` has a fill worth naming a default for — `'surface.default'`,
21
+ * so an outlined chip reads as a solid capsule rather than a ring over
22
+ * whatever it happens to sit on. Pass `'transparent'` to get the ring back.
23
+ */
24
+ background?: ColorToken;
17
25
  children?: ReactNode;
18
26
  }
19
27
 
@@ -177,9 +185,10 @@ function renderChildren(children: ReactNode): ReactNode {
177
185
  // ─── Component ────────────────────────────────────────────────────────────────
178
186
 
179
187
  const ChipRoot = forwardRef<ComponentRef<typeof View>, ChipProps>(function Chip(
180
- { size = "md", variant = "soft", color = "secondary", children, style, ...rest },
188
+ { size = "md", variant = "soft", color = "secondary", background, children, style, ...rest },
181
189
  ref
182
190
  ) {
191
+ const { theme } = useUnistyles();
183
192
  // Compound variants only match the 5 named schemes above — an arbitrary
184
193
  // literal never matches one, so it's cast to satisfy `useVariants`'s
185
194
  // literal-union type while still comparing against the real value below.
@@ -195,15 +204,20 @@ const ChipRoot = forwardRef<ComponentRef<typeof View>, ChipProps>(function Chip(
195
204
  const customPaint =
196
205
  customColors && variant !== "ghost"
197
206
  ? {
198
- backgroundColor: customColors.bg,
207
+ // Absent for outline, whose fill comes from the `outline` style
208
+ // variant — spreading `undefined` here would clear it instead.
209
+ ...(customColors.bg === undefined ? null : { backgroundColor: customColors.bg }),
199
210
  borderColor: customColors.border,
200
211
  borderWidth: customColors.borderWidth,
201
212
  }
202
213
  : null;
214
+ // Last of the paint layers, so an explicit fill beats both the variant's own
215
+ // and the one derived from a custom color literal.
216
+ const backgroundPaint = background ? { backgroundColor: resolveThemeColor(background, theme) } : null;
203
217
 
204
218
  return (
205
219
  <ChipContext.Provider value={{ color: fg, size }}>
206
- <View ref={ref} style={[styles.base, customPaint, style]} {...rest}>
220
+ <View ref={ref} style={[styles.base, customPaint, backgroundPaint, style]} {...rest}>
207
221
  {renderChildren(children)}
208
222
  </View>
209
223
  </ChipContext.Provider>
@@ -314,7 +328,11 @@ const styles = StyleSheet.create((theme) => {
314
328
  variant: {
315
329
  solid: {},
316
330
  soft: {},
317
- outline: {},
331
+ // The fill every outlined chip gets, whatever its color — the
332
+ // compound rows below only add the ring. A named default lives here
333
+ // rather than in each row so a custom color literal, which matches no
334
+ // compound row at all, is filled the same way.
335
+ outline: { backgroundColor: c["surface.default"] },
318
336
  ghost: {
319
337
  backgroundColor: "transparent",
320
338
  borderColor: "transparent",
@@ -343,7 +361,6 @@ const styles = StyleSheet.create((theme) => {
343
361
  color: "primary",
344
362
  variant: "outline",
345
363
  styles: {
346
- backgroundColor: "transparent",
347
364
  borderColor: c["accent.soft.bg"],
348
365
  borderWidth: 1,
349
366
  },
@@ -368,7 +385,6 @@ const styles = StyleSheet.create((theme) => {
368
385
  color: "secondary",
369
386
  variant: "outline",
370
387
  styles: {
371
- backgroundColor: "transparent",
372
388
  borderColor: c["neutral.soft.bg"],
373
389
  borderWidth: 1,
374
390
  },
@@ -393,7 +409,6 @@ const styles = StyleSheet.create((theme) => {
393
409
  color: "success",
394
410
  variant: "outline",
395
411
  styles: {
396
- backgroundColor: "transparent",
397
412
  borderColor: c["success.soft.bg"],
398
413
  borderWidth: 1,
399
414
  },
@@ -418,7 +433,6 @@ const styles = StyleSheet.create((theme) => {
418
433
  color: "warning",
419
434
  variant: "outline",
420
435
  styles: {
421
- backgroundColor: "transparent",
422
436
  borderColor: c["warning.soft.bg"],
423
437
  borderWidth: 1,
424
438
  },
@@ -443,7 +457,6 @@ const styles = StyleSheet.create((theme) => {
443
457
  color: "danger",
444
458
  variant: "outline",
445
459
  styles: {
446
- backgroundColor: "transparent",
447
460
  borderColor: c["danger.soft.bg"],
448
461
  borderWidth: 1,
449
462
  },
@@ -6,7 +6,12 @@ import { readableOn, withAlpha } from "#utils/color-utils";
6
6
  // full color scheme.
7
7
 
8
8
  export interface CustomChipColors {
9
- bg: string;
9
+ /**
10
+ * Undefined for `outline`, which takes the fill its style variant paints
11
+ * rather than deriving one — the outlined chip's fill is a surface, not a
12
+ * tint of the literal, so there is nothing here to derive it from.
13
+ */
14
+ bg: string | undefined;
10
15
  border: string;
11
16
  borderWidth: number;
12
17
  fg: string;
@@ -22,7 +27,7 @@ export function getCustomColorColors(
22
27
  // read as the same weight of colour — one filled, one drawn.
23
28
  if (variant === "outline") {
24
29
  return {
25
- bg: "transparent",
30
+ bg: undefined,
26
31
  border: withAlpha(literal, CUSTOM_COLOR_SOFT_ALPHA),
27
32
  borderWidth: 1,
28
33
  fg: literal,
@@ -7,6 +7,7 @@ export {
7
7
  type HeaderDismissNavigation,
8
8
  type HeaderDismissProps,
9
9
  } from "./header-buttons";
10
+ export type { HeaderAccessoryBehavior, HeaderAccessoryPadding } from "./types";
10
11
  export type { LargeTitleHeaderProps } from "./variants/LargeTitleHeader";
11
12
  export { LargeTitleHeader } from "./variants/LargeTitleHeader";
12
13
  export type { TitleHeaderProps } from "./variants/TitleHeader";
@@ -0,0 +1,55 @@
1
+ import { type ReactNode, useCallback, useEffect } from "react";
2
+ import { type LayoutChangeEvent, type StyleProp, View, type ViewStyle } from "react-native";
3
+
4
+ import Animated from "react-native-reanimated";
5
+ import { StyleSheet } from "react-native-unistyles";
6
+
7
+ import type { HeaderAccessoryPadding } from "../types";
8
+
9
+ export interface HeaderAccessoryProps {
10
+ children: ReactNode;
11
+ /** Horizontal padding around the accessory. */
12
+ padding: HeaderAccessoryPadding;
13
+ /** Reports layout height in dp; reports zero on cleanup to release reserved space. */
14
+ onHeightChange: (height: number) => void;
15
+ /** Additional styles for the accessory container. */
16
+ style?: StyleProp<ViewStyle>;
17
+ }
18
+
19
+ /** Measures accessory content so the header can reserve space in the scroll container. */
20
+ export function HeaderAccessory({ children, padding, onHeightChange, style }: HeaderAccessoryProps) {
21
+ const handleLayout = useCallback(
22
+ (event: LayoutChangeEvent) => {
23
+ onHeightChange(event.nativeEvent.layout.height);
24
+ },
25
+ [onHeightChange]
26
+ );
27
+
28
+ // Release the previous owner’s space when the callback changes or the accessory unmounts.
29
+ useEffect(() => () => onHeightChange(0), [onHeightChange]);
30
+
31
+ styles.useVariants({ padding });
32
+
33
+ return (
34
+ <Animated.View style={[styles.accessory, style]} onLayout={handleLayout}>
35
+ {children}
36
+ </Animated.View>
37
+ );
38
+ }
39
+
40
+ /** Reserves scroll-content space for the sticky accessory rendered in the header overlay. */
41
+ export function HeaderAccessorySpacer({ height }: { height: number }) {
42
+ return <View style={styles.spacer(height)} />;
43
+ }
44
+
45
+ const styles = StyleSheet.create((theme) => ({
46
+ accessory: {
47
+ variants: {
48
+ padding: {
49
+ x: { paddingHorizontal: theme.layout.screen.padding.x },
50
+ none: {},
51
+ },
52
+ },
53
+ },
54
+ spacer: (height: number) => ({ height }),
55
+ }));
@@ -0,0 +1,62 @@
1
+ import { View } from "react-native";
2
+
3
+ import Animated, { type useAnimatedStyle } from "react-native-reanimated";
4
+ import { StyleSheet } from "react-native-unistyles";
5
+
6
+ import { HEADER_FADE_EXTENT, HeaderGradientOverlay } from "./HeaderGradientOverlay";
7
+
8
+ type HeaderOpacityStyle = ReturnType<typeof useAnimatedStyle<{ opacity: number }>>;
9
+
10
+ export interface HeaderSurfaceProps {
11
+ /** Fill color, fading to fully transparent along the bottom edge. */
12
+ color: string;
13
+ /** Opacity style for variants that fade the whole surface in as they collapse. */
14
+ animatedStyle?: HeaderOpacityStyle;
15
+ /**
16
+ * Height of the bottom gradient in dp. The region above it uses a solid fill.
17
+ * @defaultValue The themed bar height plus `HEADER_FADE_EXTENT`.
18
+ */
19
+ fadeHeight?: number;
20
+ }
21
+
22
+ /**
23
+ * Header background with a solid fill and a bottom gradient.
24
+ * A fixed gradient height keeps tall accessories from becoming translucent.
25
+ */
26
+ export function HeaderSurface({ color, animatedStyle, fadeHeight }: HeaderSurfaceProps) {
27
+ return (
28
+ <Animated.View style={[styles.surface, animatedStyle]} pointerEvents="none">
29
+ <View style={styles.fill(color, fadeHeight)} />
30
+ <View style={styles.fade(fadeHeight)}>
31
+ <HeaderGradientOverlay color={color} />
32
+ </View>
33
+ </Animated.View>
34
+ );
35
+ }
36
+
37
+ const styles = StyleSheet.create((theme) => ({
38
+ // Extend the fade below the header's layout bounds.
39
+ surface: {
40
+ position: "absolute",
41
+ top: 0,
42
+ left: 0,
43
+ right: 0,
44
+ bottom: -HEADER_FADE_EXTENT,
45
+ },
46
+ // Fill the region above the gradient.
47
+ fill: (color: string, fadeHeight: number | undefined) => ({
48
+ position: "absolute",
49
+ top: 0,
50
+ left: 0,
51
+ right: 0,
52
+ bottom: fadeHeight ?? theme.layout.header.height + HEADER_FADE_EXTENT,
53
+ backgroundColor: color,
54
+ }),
55
+ fade: (fadeHeight: number | undefined) => ({
56
+ position: "absolute",
57
+ left: 0,
58
+ right: 0,
59
+ bottom: 0,
60
+ height: fadeHeight ?? theme.layout.header.height + HEADER_FADE_EXTENT,
61
+ }),
62
+ }));
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Horizontal padding around a header accessory.
3
+ * - `'x'`: match the header bar's horizontal padding.
4
+ * - `'none'`: extend to the screen edges, for example for a scrollable tab strip.
5
+ */
6
+ export type HeaderAccessoryPadding = "x" | "none";
7
+
8
+ /**
9
+ * Accessory placement while a large-title header scrolls.
10
+ * - `'pinned'`: remain directly below the compact bar.
11
+ * - `'sticky'`: scroll with the large title, then pin below the compact bar.
12
+ *
13
+ * Used by `Header.LargeTitle`. A hidden large title always uses pinned placement.
14
+ */
15
+ export type HeaderAccessoryBehavior = "pinned" | "sticky";
@@ -1,5 +1,5 @@
1
- import { useEffect } from "react";
2
- import { Text, View } from "react-native";
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import { type LayoutChangeEvent, Text, View } from "react-native";
3
3
 
4
4
  import Animated, { interpolate, useAnimatedStyle, useSharedValue } from "react-native-reanimated";
5
5
  import { StyleSheet, useUnistyles } from "react-native-unistyles";
@@ -11,7 +11,10 @@ import { useHeaderBackground } from "../../../screen/parts/ScreenHeaderAppearanc
11
11
  import { SCREEN_HEADER_PORTAL_HOST, useScreen } from "../../../screen/ScreenContext";
12
12
  import { Toolbar } from "../../../toolbar";
13
13
  import { HeaderDismissButton } from "../../header-buttons";
14
- import { HEADER_FADE_EXTENT, HeaderGradientOverlay } from "../../parts/HeaderGradientOverlay";
14
+ import { HeaderAccessory, HeaderAccessorySpacer } from "../../parts/HeaderAccessory";
15
+ import { HEADER_FADE_EXTENT } from "../../parts/HeaderGradientOverlay";
16
+ import { HeaderSurface } from "../../parts/HeaderSurface";
17
+ import type { HeaderAccessoryBehavior } from "../../types";
15
18
  import { isCustomTitle, isTextTitle } from "../../utils";
16
19
  import type { TitleHeaderProps } from "../TitleHeader";
17
20
 
@@ -29,6 +32,12 @@ export interface LargeTitleHeaderProps extends TitleHeaderProps {
29
32
  subtitle?: string;
30
33
  /** Hide the large title (keeps the compact bar). Defaults to `false`. */
31
34
  isLargeTitleHidden?: boolean;
35
+ /**
36
+ * How `accessory` moves while scrolling. `'sticky'` starts below the large title
37
+ * and pins below the compact bar when scrolled up. A hidden large title always pins.
38
+ * @defaultValue 'pinned'
39
+ */
40
+ accessoryBehavior?: HeaderAccessoryBehavior;
32
41
  /**
33
42
  * Placement of the compact bar title. The large title stack always stays
34
43
  * left-aligned. Defaults to `'center'`.
@@ -40,7 +49,11 @@ function LargeTitlePortalContent({
40
49
  title,
41
50
  overline,
42
51
  subtitle,
43
- }: Pick<LargeTitleHeaderProps, "title" | "overline" | "subtitle">) {
52
+ onHeightChange,
53
+ }: Pick<LargeTitleHeaderProps, "title" | "overline" | "subtitle"> & {
54
+ /** Reports the large-title block's layout height in dp. */
55
+ onHeightChange?: (height: number) => void;
56
+ }) {
44
57
  const { theme } = useUnistyles();
45
58
  const { scrollY } = useScreen();
46
59
 
@@ -62,8 +75,11 @@ function LargeTitlePortalContent({
62
75
  };
63
76
  });
64
77
 
78
+ // Layout height excludes the collapse transform.
79
+ const handleLayout = (event: LayoutChangeEvent) => onHeightChange?.(event.nativeEvent.layout.height);
80
+
65
81
  return (
66
- <Animated.View style={[styles.portalContent, largeTitleAnimatedStyle]}>
82
+ <Animated.View style={[styles.portalContent, largeTitleAnimatedStyle]} onLayout={handleLayout}>
67
83
  {!!overline && (
68
84
  <Text
69
85
  style={styles.overline}
@@ -123,6 +139,9 @@ export function LargeTitleHeader({
123
139
  trailingActions,
124
140
  LeftToolbar,
125
141
  RightToolbar,
142
+ accessory,
143
+ accessoryPadding = "x",
144
+ accessoryBehavior = "pinned",
126
145
  dismissAction = "none",
127
146
  navigation,
128
147
  onDismiss,
@@ -133,7 +152,7 @@ export function LargeTitleHeader({
133
152
  }: LargeTitleHeaderProps) {
134
153
  const { theme } = useUnistyles();
135
154
 
136
- const { scrollY, background: screenBackground } = useScreen();
155
+ const { scrollY, background: screenBackground, setHeaderAccessoryHeight, contentTopPadding } = useScreen();
137
156
  const colorToken = background ?? bg;
138
157
  const bgColor =
139
158
  (colorToken ? resolveThemeColor(colorToken, theme) : screenBackground) ?? theme.color["surface.canvas"];
@@ -141,7 +160,39 @@ export function LargeTitleHeader({
141
160
  const trailingContent = trailingActions !== undefined ? trailingActions : RightToolbar;
142
161
 
143
162
  const gradientColor = bgColor;
163
+ const isSticky = accessoryBehavior === "sticky" && !isLargeTitleHidden;
164
+ // Sticky accessories reserve space below the large title; pinned ones add top padding.
165
+ const [stickyAccessoryHeight, setStickyAccessoryHeight] = useState(0);
166
+ const [largeTitleHeight, setLargeTitleHeight] = useState(0);
144
167
  const isLargeTitleHiddenValue = useSharedValue(isLargeTitleHidden);
168
+
169
+ const handleAccessoryHeightChange = useCallback(
170
+ (height: number) => {
171
+ if (isSticky) setStickyAccessoryHeight(Math.max(0, Math.round(height)));
172
+ else setHeaderAccessoryHeight(height);
173
+ },
174
+ [isSticky, setHeaderAccessoryHeight]
175
+ );
176
+
177
+ const handleLargeTitleHeightChange = useCallback((height: number) => {
178
+ setLargeTitleHeight(Math.max(0, Math.round(height)));
179
+ }, []);
180
+
181
+ // Rest below the title, including the scroll container's top padding.
182
+ const stickyAccessoryOffset = Math.max(
183
+ 0,
184
+ contentTopPadding + largeTitleHeight - theme.layout.header.height
185
+ );
186
+
187
+ // Zero translation places the accessory directly below the compact bar.
188
+ const stickyAccessoryStyle = useAnimatedStyle(() => {
189
+ if (isLargeTitleHiddenValue.value) {
190
+ return { transform: [{ translateY: 0 }] };
191
+ }
192
+ return {
193
+ transform: [{ translateY: Math.max(0, stickyAccessoryOffset - scrollY.value) }],
194
+ };
195
+ });
145
196
  const headerCollapseHeight = theme.layout.header.height;
146
197
  styles.useVariants({ titleAlignment });
147
198
 
@@ -209,56 +260,77 @@ export function LargeTitleHeader({
209
260
  );
210
261
 
211
262
  return (
212
- <View style={styles.container}>
263
+ // Let touches in the expanded header's empty space reach the scroll content.
264
+ <View style={styles.container(isSticky ? stickyAccessoryOffset : 0)} pointerEvents="box-none">
213
265
  {!isLargeTitleHidden && (
214
266
  <Portal hostName={SCREEN_HEADER_PORTAL_HOST}>
215
- <LargeTitlePortalContent title={title} overline={overline} subtitle={subtitle} />
267
+ <LargeTitlePortalContent
268
+ title={title}
269
+ overline={overline}
270
+ subtitle={subtitle}
271
+ onHeightChange={isSticky ? handleLargeTitleHeightChange : undefined}
272
+ />
273
+ {/* Reserve space for the accessory rendered in the overlay. */}
274
+ {isSticky && accessory != null && <HeaderAccessorySpacer height={stickyAccessoryHeight} />}
216
275
  </Portal>
217
276
  )}
218
- <View style={styles.bar}>
219
- <Animated.View style={[styles.gradient, gradientOpacityStyle]} pointerEvents="none">
220
- <HeaderGradientOverlay color={gradientColor} />
221
- </Animated.View>
222
- {leading != null && <Toolbar>{leading}</Toolbar>}
223
- {/* Text can never be the touch target, but custom content may be, so its
224
- container passes touches through to it instead of swallowing them. */}
225
- <Animated.View
226
- style={[styles.titleContainer, compactTitleAnimatedStyle]}
227
- pointerEvents={isCustomTitle(title) ? "box-none" : "none"}
228
- >
229
- {isTextTitle(title) ? (
230
- <AnimatedText
231
- style={styles.compactTitle}
232
- maxFontSizeMultiplier={theme.typography.variants["title-md"].maxFontSizeMultiplier}
233
- >
234
- {title}
235
- </AnimatedText>
236
- ) : (
237
- title
238
- )}
239
- </Animated.View>
240
- {trailing != null && <Toolbar style={styles.trailing}>{trailing}</Toolbar>}
277
+ {/* Share a background between the bar and a pinned accessory. */}
278
+ <View style={styles.barGroup}>
279
+ <HeaderSurface color={gradientColor} animatedStyle={gradientOpacityStyle} />
280
+ <View style={styles.bar}>
281
+ {leading != null && <Toolbar>{leading}</Toolbar>}
282
+ {/* Text can never be the touch target, but custom content may be, so its
283
+ container passes touches through to it instead of swallowing them. */}
284
+ <Animated.View
285
+ style={[styles.titleContainer, compactTitleAnimatedStyle]}
286
+ pointerEvents={isCustomTitle(title) ? "box-none" : "none"}
287
+ >
288
+ {isTextTitle(title) ? (
289
+ <AnimatedText
290
+ style={styles.compactTitle}
291
+ maxFontSizeMultiplier={theme.typography.variants["title-md"].maxFontSizeMultiplier}
292
+ >
293
+ {title}
294
+ </AnimatedText>
295
+ ) : (
296
+ title
297
+ )}
298
+ </Animated.View>
299
+ {trailing != null && <Toolbar style={styles.trailing}>{trailing}</Toolbar>}
300
+ </View>
301
+ {accessory != null && !isSticky && (
302
+ <HeaderAccessory padding={accessoryPadding} onHeightChange={handleAccessoryHeightChange}>
303
+ {accessory}
304
+ </HeaderAccessory>
305
+ )}
241
306
  </View>
307
+ {accessory != null && isSticky && (
308
+ // The background moves with the sticky accessory.
309
+ <Animated.View style={[styles.stickyAccessory, stickyAccessoryStyle]}>
310
+ <HeaderSurface color={gradientColor} fadeHeight={HEADER_FADE_EXTENT} />
311
+ <HeaderAccessory padding={accessoryPadding} onHeightChange={handleAccessoryHeightChange}>
312
+ {accessory}
313
+ </HeaderAccessory>
314
+ </Animated.View>
315
+ )}
242
316
  </View>
243
317
  );
244
318
  }
245
319
 
246
320
  const styles = StyleSheet.create((theme) => ({
247
- container: {
321
+ // Include the translated accessory in the parent's touchable bounds.
322
+ container: (accessoryOffset: number) => ({
248
323
  position: "absolute",
249
324
  top: 0,
250
325
  left: 0,
251
326
  right: 0,
252
327
  zIndex: 1000,
253
- },
254
- // Let the fade extend below the bar without intercepting touches.
255
- gradient: {
256
- position: "absolute",
257
- top: 0,
258
- left: 0,
259
- right: 0,
260
- bottom: -HEADER_FADE_EXTENT,
261
- },
328
+ paddingBottom: accessoryOffset,
329
+ }),
330
+ // Normal flow places the accessory directly below the bar.
331
+ stickyAccessory: { position: "relative" },
332
+ // Anchors the absolutely positioned surface over the bar and the accessory both.
333
+ barGroup: { position: "relative" },
262
334
  bar: {
263
335
  height: theme.layout.header.height,
264
336
  flexDirection: "row",
@@ -282,7 +354,7 @@ const styles = StyleSheet.create((theme) => ({
282
354
  portalContent: {
283
355
  gap: 2,
284
356
  minHeight: theme.layout.header.height,
285
- paddingBottom: theme.spacing["3"],
357
+ paddingBottom: theme.spacing["1"],
286
358
  paddingHorizontal: theme.layout.screen.padding.x,
287
359
  },
288
360
  overline: {