react-native-terra-ui 0.11.17 → 0.12.1

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 (109) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/lib/module/components/accordion/Accordion.js +109 -0
  3. package/lib/module/components/accordion/Accordion.js.map +1 -0
  4. package/lib/module/components/accordion/context.js +34 -0
  5. package/lib/module/components/accordion/context.js.map +1 -0
  6. package/lib/module/components/accordion/hooks/use-accordion-core.js +46 -0
  7. package/lib/module/components/accordion/hooks/use-accordion-core.js.map +1 -0
  8. package/lib/module/components/accordion/index.js +5 -0
  9. package/lib/module/components/accordion/index.js.map +1 -0
  10. package/lib/module/components/accordion/parts/AccordionContent.js +98 -0
  11. package/lib/module/components/accordion/parts/AccordionContent.js.map +1 -0
  12. package/lib/module/components/accordion/parts/AccordionIndicator.js +60 -0
  13. package/lib/module/components/accordion/parts/AccordionIndicator.js.map +1 -0
  14. package/lib/module/components/accordion/parts/AccordionItem.js +53 -0
  15. package/lib/module/components/accordion/parts/AccordionItem.js.map +1 -0
  16. package/lib/module/components/accordion/parts/AccordionTrigger.js +85 -0
  17. package/lib/module/components/accordion/parts/AccordionTrigger.js.map +1 -0
  18. package/lib/module/components/accordion/types.js +4 -0
  19. package/lib/module/components/accordion/types.js.map +1 -0
  20. package/lib/module/components/accordion/utils.js +15 -0
  21. package/lib/module/components/accordion/utils.js.map +1 -0
  22. package/lib/module/components/avatar/Avatar.js +15 -3
  23. package/lib/module/components/avatar/Avatar.js.map +1 -1
  24. package/lib/module/components/badge/Badge.js +220 -64
  25. package/lib/module/components/badge/Badge.js.map +1 -1
  26. package/lib/module/components/badge/WithBadge.js +94 -0
  27. package/lib/module/components/badge/WithBadge.js.map +1 -0
  28. package/lib/module/components/badge/index.js +1 -0
  29. package/lib/module/components/badge/index.js.map +1 -1
  30. package/lib/module/components/badge/utils.js +3 -3
  31. package/lib/module/components/chip/Chip.js +1 -0
  32. package/lib/module/components/chip/Chip.js.map +1 -1
  33. package/lib/module/components/header/parts/HeaderBar.js +105 -69
  34. package/lib/module/components/header/parts/HeaderBar.js.map +1 -1
  35. package/lib/module/components/header/variants/LargeTitleHeader/parts/LargeTitleContent.js +50 -33
  36. package/lib/module/components/header/variants/LargeTitleHeader/parts/LargeTitleContent.js.map +1 -1
  37. package/lib/module/components/index.js +1 -0
  38. package/lib/module/components/index.js.map +1 -1
  39. package/lib/module/components/input/parts/InputField.js +96 -82
  40. package/lib/module/components/input/parts/InputField.js.map +1 -1
  41. package/lib/module/components/text/Text.js +10 -6
  42. package/lib/module/components/text/Text.js.map +1 -1
  43. package/lib/module/theme/tokens/primitives.js +24 -4
  44. package/lib/module/theme/tokens/primitives.js.map +1 -1
  45. package/lib/typescript/src/components/accordion/Accordion.d.ts +33 -0
  46. package/lib/typescript/src/components/accordion/Accordion.d.ts.map +1 -0
  47. package/lib/typescript/src/components/accordion/context.d.ts +25 -0
  48. package/lib/typescript/src/components/accordion/context.d.ts.map +1 -0
  49. package/lib/typescript/src/components/accordion/hooks/use-accordion-core.d.ts +11 -0
  50. package/lib/typescript/src/components/accordion/hooks/use-accordion-core.d.ts.map +1 -0
  51. package/lib/typescript/src/components/accordion/index.d.ts +8 -0
  52. package/lib/typescript/src/components/accordion/index.d.ts.map +1 -0
  53. package/lib/typescript/src/components/accordion/parts/AccordionContent.d.ts +8 -0
  54. package/lib/typescript/src/components/accordion/parts/AccordionContent.d.ts.map +1 -0
  55. package/lib/typescript/src/components/accordion/parts/AccordionIndicator.d.ts +16 -0
  56. package/lib/typescript/src/components/accordion/parts/AccordionIndicator.d.ts.map +1 -0
  57. package/lib/typescript/src/components/accordion/parts/AccordionItem.d.ts +16 -0
  58. package/lib/typescript/src/components/accordion/parts/AccordionItem.d.ts.map +1 -0
  59. package/lib/typescript/src/components/accordion/parts/AccordionTrigger.d.ts +11 -0
  60. package/lib/typescript/src/components/accordion/parts/AccordionTrigger.d.ts.map +1 -0
  61. package/lib/typescript/src/components/accordion/types.d.ts +65 -0
  62. package/lib/typescript/src/components/accordion/types.d.ts.map +1 -0
  63. package/lib/typescript/src/components/accordion/utils.d.ts +8 -0
  64. package/lib/typescript/src/components/accordion/utils.d.ts.map +1 -0
  65. package/lib/typescript/src/components/avatar/Avatar.d.ts.map +1 -1
  66. package/lib/typescript/src/components/badge/Badge.d.ts +13 -9
  67. package/lib/typescript/src/components/badge/Badge.d.ts.map +1 -1
  68. package/lib/typescript/src/components/badge/WithBadge.d.ts +18 -0
  69. package/lib/typescript/src/components/badge/WithBadge.d.ts.map +1 -0
  70. package/lib/typescript/src/components/badge/index.d.ts +2 -1
  71. package/lib/typescript/src/components/badge/index.d.ts.map +1 -1
  72. package/lib/typescript/src/components/badge/types.d.ts +35 -12
  73. package/lib/typescript/src/components/badge/types.d.ts.map +1 -1
  74. package/lib/typescript/src/components/badge/utils.d.ts +3 -3
  75. package/lib/typescript/src/components/badge/utils.d.ts.map +1 -1
  76. package/lib/typescript/src/components/header/parts/HeaderBar.d.ts.map +1 -1
  77. package/lib/typescript/src/components/index.d.ts +1 -0
  78. package/lib/typescript/src/components/index.d.ts.map +1 -1
  79. package/lib/typescript/src/components/input/parts/InputField.d.ts.map +1 -1
  80. package/lib/typescript/src/theme/tokens/primitives.d.ts.map +1 -1
  81. package/package.json +1 -1
  82. package/src/components/accordion/Accordion.tsx +116 -0
  83. package/src/components/accordion/context.ts +45 -0
  84. package/src/components/accordion/hooks/use-accordion-core.ts +51 -0
  85. package/src/components/accordion/index.ts +14 -0
  86. package/src/components/accordion/parts/AccordionContent.tsx +96 -0
  87. package/src/components/accordion/parts/AccordionIndicator.tsx +67 -0
  88. package/src/components/accordion/parts/AccordionItem.tsx +55 -0
  89. package/src/components/accordion/parts/AccordionTrigger.tsx +88 -0
  90. package/src/components/accordion/types.ts +71 -0
  91. package/src/components/accordion/utils.ts +12 -0
  92. package/src/components/avatar/Avatar.tsx +12 -2
  93. package/src/components/badge/Badge.tsx +178 -59
  94. package/src/components/badge/WithBadge.tsx +79 -0
  95. package/src/components/badge/index.ts +2 -1
  96. package/src/components/badge/types.ts +36 -12
  97. package/src/components/badge/utils.ts +3 -3
  98. package/src/components/chip/Chip.tsx +1 -0
  99. package/src/components/header/parts/HeaderBar.tsx +100 -57
  100. package/src/components/header/variants/LargeTitleHeader/parts/LargeTitleContent.tsx +47 -29
  101. package/src/components/index.ts +1 -0
  102. package/src/components/input/parts/InputField.tsx +63 -55
  103. package/src/components/text/Text.tsx +10 -6
  104. package/src/theme/tokens/primitives.ts +24 -4
  105. package/lib/module/components/badge/parts/BadgeIndicator.js +0 -212
  106. package/lib/module/components/badge/parts/BadgeIndicator.js.map +0 -1
  107. package/lib/typescript/src/components/badge/parts/BadgeIndicator.d.ts +0 -19
  108. package/lib/typescript/src/components/badge/parts/BadgeIndicator.d.ts.map +0 -1
  109. package/src/components/badge/parts/BadgeIndicator.tsx +0 -178
@@ -1,49 +1,72 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { ViewProps } from "react-native";
3
- /** Corner of the wrapped child the indicator is anchored to. */
3
+ /** Corner of the wrapped child a `WithBadge` anchors its badge to. */
4
4
  export type BadgePlacement = "top-right" | "top-left" | "bottom-right" | "bottom-left";
5
5
  /** Scale of the dot, pill, and label. */
6
6
  export type BadgeSize = "sm" | "md" | "lg";
7
7
  /**
8
8
  * Semantic color scheme, or a raw CSS color literal (`#fff`, `rgb(...)`, `hsl(...)`).
9
- * A literal paints the indicator with that exact value and derives a readable
9
+ * A literal paints the badge with that exact value and derives a readable
10
10
  * foreground for the label.
11
11
  */
12
12
  export type BadgeColor = "primary" | "secondary" | "success" | "warning" | "danger" | (string & {});
13
- export interface BadgeProps extends ViewProps {
14
- /** The element being badged. Rendered untouched; `Badge` only adds the overlay. */
13
+ export interface BadgeProps extends Omit<ViewProps, "children"> {
14
+ /**
15
+ * Text in the badge. Omit it (or pass an empty string) for a dot.
16
+ * `0` renders as a label; a caller hiding a zero count leaves the badge out.
17
+ */
18
+ label?: string | number;
19
+ /** Semantic scheme or raw color literal. Defaults to `'danger'`. */
20
+ color?: BadgeColor;
21
+ /** Scale of the badge. Defaults to `'md'`. */
22
+ size?: BadgeSize;
23
+ /**
24
+ * Draws a `surface.canvas` ring around the badge, so it stays legible over
25
+ * whatever it overlaps. `WithBadge` turns it on. A badge inline beside text
26
+ * overlaps nothing, so it defaults to `false`: on a card the ring would only
27
+ * read as an outline.
28
+ */
29
+ ring?: boolean;
30
+ /**
31
+ * Announced in place of the label. Defaults to the label's own text; an
32
+ * unlabelled dot is hidden from assistive technology.
33
+ */
34
+ accessibilityLabel?: string;
35
+ }
36
+ export interface WithBadgeProps extends ViewProps {
37
+ /** The element being badged. Rendered untouched; `WithBadge` only adds the overlay. */
15
38
  children: ReactNode;
16
39
  /**
17
- * Corner the indicator sits on. Defaults to `'top-right'`.
40
+ * Corner the badge sits on. Defaults to `'top-right'`.
18
41
  *
19
- * The indicator overhangs the child, so an ancestor that clips — a `Surface`
42
+ * The badge overhangs the child, so an ancestor that clips — a `Surface`
20
43
  * with a radius, or a `Screen` list row — will cut it off. Pad that container
21
- * by the overhang, or lift the `Badge` outside it.
44
+ * by the overhang, or lift the `WithBadge` outside it.
22
45
  */
23
46
  placement?: BadgePlacement;
24
47
  /**
25
- * Text in the indicator. Omit it (or pass an empty string) for a dot.
48
+ * Text in the badge. Omit it (or pass an empty string) for a dot.
26
49
  * `0` renders as a label — use `isVisible` to suppress a zero count.
27
50
  */
28
51
  label?: string | number;
29
52
  /** Semantic scheme or raw color literal. Defaults to `'danger'`. */
30
53
  color?: BadgeColor;
31
- /** Scale of the indicator. Defaults to `'md'`. */
54
+ /** Scale of the badge. Defaults to `'md'`. */
32
55
  size?: BadgeSize;
33
56
  /**
34
- * Nudges the indicator along both axes from the corner `placement` picked.
57
+ * Nudges the badge along both axes from the corner `placement` picked.
35
58
  * Positive moves it away from the child's centre, negative pulls it in.
36
59
  * A number applies to both axes; `{ x, y }` sets them separately.
37
60
  *
38
61
  * The corner it anchors to is the child's **bounding box**, so a round child
39
- * needs a negative offset to bring the indicator onto the visible edge — a
62
+ * needs a negative offset to bring the badge onto the visible edge — a
40
63
  * circle only meets its box at 45°, about `0.21 × width` away. Defaults to `0`.
41
64
  */
42
65
  offset?: number | {
43
66
  x?: number;
44
67
  y?: number;
45
68
  };
46
- /** Renders the indicator. The child renders either way. Defaults to `true`. */
69
+ /** Renders the badge. The child renders either way. Defaults to `true`. */
47
70
  isVisible?: boolean;
48
71
  /**
49
72
  * Stretches the wrapper along its parent's cross axis, so a child that
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/components/badge/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,gEAAgE;AAChE,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,GAAG,aAAa,CAAC;AAEvF,yCAAyC;AACzC,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE3C;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,WAAW,GACX,SAAS,GACT,SAAS,GACT,QAAQ,GAER,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB,MAAM,WAAW,UAAW,SAAQ,SAAS;IAC3C,mFAAmF;IACnF,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,oEAAoE;IACpE,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,kDAAkD;IAClD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG;QAAE,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/components/badge/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,sEAAsE;AACtE,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,GAAG,aAAa,CAAC;AAEvF,yCAAyC;AACzC,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE3C;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,WAAW,GACX,SAAS,GACT,SAAS,GACT,QAAQ,GAER,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB,MAAM,WAAW,UAAW,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAC7D;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,oEAAoE;IACpE,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C,uFAAuF;IACvF,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,oEAAoE;IACpE,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG;QAAE,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B"}
@@ -3,7 +3,7 @@ export interface CustomBadgeColors {
3
3
  bg: string;
4
4
  fg: string;
5
5
  }
6
- /** The indicator's paint for a raw literal: the literal itself, plus a readable label. */
6
+ /** The badge's paint for a raw literal: the literal itself, plus a readable label. */
7
7
  export declare function getCustomBadgeColors(literal: string): CustomBadgeColors;
8
8
  /**
9
9
  * `true` when `label` should render as a pill. An empty string and `undefined`
@@ -12,7 +12,7 @@ export declare function getCustomBadgeColors(literal: string): CustomBadgeColors
12
12
  */
13
13
  export declare function hasLabel(label: string | number | undefined): label is string | number;
14
14
  /**
15
- * Outer diameter of the dot per size. The indicator's own stylesheet repeats
15
+ * Outer diameter of the dot per size. The badge's own stylesheet repeats
16
16
  * these as literals — the unistyles Babel plugin reads that object statically,
17
17
  * so it cannot reference this table — and `anchorOffsetsMatchDotRadius` in the
18
18
  * test suite is what keeps the two in step.
@@ -25,7 +25,7 @@ export interface AnchorPosition {
25
25
  left?: number;
26
26
  }
27
27
  /**
28
- * Absolute insets for the indicator, in pure arithmetic rather than one
28
+ * Absolute insets for a `WithBadge`'s badge, in pure arithmetic rather than one
29
29
  * compound variant per (placement, size) cell: `offset` is an open-ended number
30
30
  * and could never be a variant condition, and nothing here touches the theme.
31
31
  *
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/components/badge/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAS,CAAC;AAMzD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAEvE;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,KAAK,IAAI,MAAM,GAAG,MAAM,CAErF;AAED;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAI9C,CAAC;AAEF,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,cAAc,EACzB,IAAI,EAAE,SAAS,EACf,MAAM,GAAE,MAAM,GAAG;IAAE,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAM,GAC9C,cAAc,CAkBhB"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/components/badge/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAS,CAAC;AAMzD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,sFAAsF;AACtF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAEvE;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,KAAK,IAAI,MAAM,GAAG,MAAM,CAErF;AAED;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAI9C,CAAC;AAEF,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,cAAc,EACzB,IAAI,EAAE,SAAS,EACf,MAAM,GAAE,MAAM,GAAG;IAAE,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAM,GAC9C,cAAc,CAkBhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"HeaderBar.d.ts","sourceRoot":"","sources":["../../../../../../src/components/header/parts/HeaderBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAC;AAGtE,OAAO,QAAQ,MAAM,yBAAyB,CAAC;AAO/C,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,sBAAmB,CAAC;AAEjF,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,oBAAiB,CAAC;AAGzE,UAAU,cAAe,SAAQ,kBAAkB;IACjD,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,cAAc,EAAE,QAAQ,GAAG,MAAM,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,kBAAkB,CAAC,eAAe,CAAC,CAAC;IACnD,UAAU,CAAC,EAAE,cAAc,CAAC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;CAC5D;AAED,2FAA2F;AAC3F,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,OAAO,EACP,QAAQ,EACR,cAAc,EACd,KAAK,EACL,YAAY,EACZ,UAAU,EACV,aAAsB,EACtB,UAAU,EACV,SAAS,GACV,EAAE,cAAc,+BA6DhB"}
1
+ {"version":3,"file":"HeaderBar.d.ts","sourceRoot":"","sources":["../../../../../../src/components/header/parts/HeaderBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAC;AAGtE,OAAO,QAAQ,MAAM,yBAAyB,CAAC;AAO/C,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,sBAAmB,CAAC;AAEjF,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,oBAAiB,CAAC;AAGzE,UAAU,cAAe,SAAQ,kBAAkB;IACjD,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,cAAc,EAAE,QAAQ,GAAG,MAAM,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,kBAAkB,CAAC,eAAe,CAAC,CAAC;IACnD,UAAU,CAAC,EAAE,cAAc,CAAC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;CAC5D;AAED,2FAA2F;AAC3F,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,OAAO,EACP,QAAQ,EACR,cAAc,EACd,KAAK,EACL,YAAY,EACZ,UAAU,EACV,aAAsB,EACtB,UAAU,EACV,SAAS,GACV,EAAE,cAAc,+BA2EhB"}
@@ -1,3 +1,4 @@
1
+ export * from "./accordion/index.js";
1
2
  export * from "./avatar/index.js";
2
3
  export * from "./badge/index.js";
3
4
  export * from "./box/index.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAU,CAAC;AACzB,cAAc,kBAAS,CAAC;AACxB,cAAc,gBAAO,CAAC;AACtB,cAAc,mBAAU,CAAC;AACzB,cAAc,iBAAQ,CAAC;AACvB,cAAc,oBAAW,CAAC;AAC1B,cAAc,wBAAe,CAAC;AAC9B,cAAc,mBAAU,CAAC;AACzB,cAAc,iBAAQ,CAAC;AACvB,cAAc,kBAAS,CAAC;AACxB,cAAc,kBAAS,CAAC;AACxB,cAAc,2BAAkB,CAAC;AACjC,cAAc,mBAAU,CAAC;AACzB,cAAc,sBAAa,CAAC;AAC5B,cAAc,mBAAU,CAAC;AACzB,cAAc,iBAAQ,CAAC;AACvB,cAAc,oBAAW,CAAC;AAC1B,cAAc,oBAAW,CAAC;AAC1B,cAAc,iBAAQ,CAAC;AACvB,cAAc,kBAAS,CAAC;AACxB,cAAc,oBAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAa,CAAC;AAC5B,cAAc,mBAAU,CAAC;AACzB,cAAc,kBAAS,CAAC;AACxB,cAAc,gBAAO,CAAC;AACtB,cAAc,mBAAU,CAAC;AACzB,cAAc,iBAAQ,CAAC;AACvB,cAAc,oBAAW,CAAC;AAC1B,cAAc,wBAAe,CAAC;AAC9B,cAAc,mBAAU,CAAC;AACzB,cAAc,iBAAQ,CAAC;AACvB,cAAc,kBAAS,CAAC;AACxB,cAAc,kBAAS,CAAC;AACxB,cAAc,2BAAkB,CAAC;AACjC,cAAc,mBAAU,CAAC;AACzB,cAAc,sBAAa,CAAC;AAC5B,cAAc,mBAAU,CAAC;AACzB,cAAc,iBAAQ,CAAC;AACvB,cAAc,oBAAW,CAAC;AAC1B,cAAc,oBAAW,CAAC;AAC1B,cAAc,iBAAQ,CAAC;AACvB,cAAc,kBAAS,CAAC;AACxB,cAAc,oBAAW,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"InputField.d.ts","sourceRoot":"","sources":["../../../../../../src/components/input/parts/InputField.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAa,MAAM,aAAU,CAAC;AAS1D;;;;GAIG;AACH,eAAO,MAAM,UAAU,oMAuDrB,CAAC"}
1
+ {"version":3,"file":"InputField.d.ts","sourceRoot":"","sources":["../../../../../../src/components/input/parts/InputField.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAa,MAAM,aAAU,CAAC;AAS1D;;;;GAIG;AACH,eAAO,MAAM,UAAU,oMA0DrB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../../../../src/theme/tokens/primitives.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0ctB,CAAC"}
1
+ {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../../../../src/theme/tokens/primitives.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8dtB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-terra-ui",
3
- "version": "0.11.17",
3
+ "version": "0.12.1",
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",
@@ -0,0 +1,116 @@
1
+ import {
2
+ Children,
3
+ type ComponentRef,
4
+ Fragment,
5
+ forwardRef,
6
+ isValidElement,
7
+ type ReactNode,
8
+ useMemo,
9
+ } from "react";
10
+ import { View } from "react-native";
11
+
12
+ import { StyleSheet } from "react-native-unistyles";
13
+
14
+ import { Divider } from "../divider";
15
+ import { AccordionContext } from "./context";
16
+ import { useAccordionCore } from "./hooks/use-accordion-core";
17
+ import { AccordionContent } from "./parts/AccordionContent";
18
+ import { AccordionIndicator } from "./parts/AccordionIndicator";
19
+ import { AccordionItem } from "./parts/AccordionItem";
20
+ import { AccordionTrigger } from "./parts/AccordionTrigger";
21
+ import type { AccordionProps } from "./types";
22
+
23
+ /**
24
+ * Puts a rule between each pair of items. The rule is a sibling rather than a
25
+ * border on the item, because an item cannot tell whether it is the last one.
26
+ * A fragment counts as one child, so items spread from a fragment share no rules.
27
+ */
28
+ function interleaveDividers(children: ReactNode): ReactNode {
29
+ const items = Children.toArray(children).filter(isValidElement);
30
+ return items.map((child, index) => (
31
+ <Fragment key={child.key ?? index}>
32
+ {index > 0 && <Divider />}
33
+ {child}
34
+ </Fragment>
35
+ ));
36
+ }
37
+
38
+ /**
39
+ * A vertical stack of headers that each open a panel of content.
40
+ *
41
+ * `'single'` mode (the default) keeps one item open at a time; `'multiple'`
42
+ * lets any number be open. Uncontrolled through `defaultValue`, or controlled
43
+ * through `value` + `onValueChange`.
44
+ *
45
+ * @example
46
+ * <Accordion defaultValue="shipping">
47
+ * <Accordion.Item value="shipping">
48
+ * <Accordion.Trigger>
49
+ * How long does shipping take?
50
+ * <Accordion.Indicator />
51
+ * </Accordion.Trigger>
52
+ * <Accordion.Content>3–5 business days.</Accordion.Content>
53
+ * </Accordion.Item>
54
+ * </Accordion>
55
+ */
56
+ const AccordionRoot = forwardRef<ComponentRef<typeof View>, AccordionProps>(function Accordion(props, ref) {
57
+ const {
58
+ selectionMode: _selectionMode,
59
+ value: _value,
60
+ defaultValue: _defaultValue,
61
+ onValueChange: _onValueChange,
62
+ isCollapsible: _isCollapsible,
63
+ variant = "plain",
64
+ divided = true,
65
+ isDisabled = false,
66
+ children,
67
+ style,
68
+ ...rest
69
+ } = props;
70
+
71
+ const { expanded, toggle } = useAccordionCore(props);
72
+ const context = useMemo(() => ({ expanded, toggle, isDisabled }), [expanded, toggle, isDisabled]);
73
+
74
+ styles.useVariants({ variant });
75
+
76
+ return (
77
+ <AccordionContext.Provider value={context}>
78
+ <View ref={ref} style={[styles.root, style]} {...rest}>
79
+ {divided ? interleaveDividers(children) : children}
80
+ </View>
81
+ </AccordionContext.Provider>
82
+ );
83
+ });
84
+
85
+ type AccordionComponent = typeof AccordionRoot & {
86
+ Item: typeof AccordionItem;
87
+ Trigger: typeof AccordionTrigger;
88
+ Indicator: typeof AccordionIndicator;
89
+ Content: typeof AccordionContent;
90
+ };
91
+
92
+ export const Accordion = AccordionRoot as AccordionComponent;
93
+ Accordion.Item = AccordionItem;
94
+ Accordion.Trigger = AccordionTrigger;
95
+ Accordion.Indicator = AccordionIndicator;
96
+ Accordion.Content = AccordionContent;
97
+
98
+ // ─── Styles ───────────────────────────────────────────────────────────────────
99
+
100
+ const styles = StyleSheet.create((theme) => ({
101
+ root: {
102
+ variants: {
103
+ variant: {
104
+ plain: {},
105
+ // A fixed radius rather than the registry's `surface` default: the
106
+ // accordion is not a `Surface`, and a configured shadow would sit oddly
107
+ // under a container whose height animates.
108
+ surface: {
109
+ backgroundColor: theme.color["surface.default"],
110
+ borderRadius: theme.radius.xl,
111
+ paddingHorizontal: theme.spacing["4"],
112
+ },
113
+ },
114
+ },
115
+ },
116
+ }));
@@ -0,0 +1,45 @@
1
+ import { createContext, useContext } from "react";
2
+
3
+ import type { AccordionItemContextValue } from "./types";
4
+
5
+ export interface AccordionContextValue {
6
+ /** Open item values. Always an array, whatever the selection mode. */
7
+ expanded: readonly string[];
8
+ toggle: (value: string) => void;
9
+ isDisabled: boolean;
10
+ }
11
+
12
+ export const AccordionContext = createContext<AccordionContextValue | null>(null);
13
+
14
+ export const AccordionItemContext = createContext<AccordionItemContextValue | null>(null);
15
+
16
+ export function useAccordionContext(): AccordionContextValue {
17
+ const context = useContext(AccordionContext);
18
+ if (!context) {
19
+ throw new Error("Accordion.Item must be rendered inside <Accordion>.");
20
+ }
21
+ return context;
22
+ }
23
+
24
+ /**
25
+ * Reads the enclosing `Accordion.Item`: whether it is open or disabled, and a
26
+ * `toggle` that follows the accordion's selection rules. Use it to build a
27
+ * custom trigger or indicator.
28
+ *
29
+ * @throws When called outside an `Accordion.Item`.
30
+ *
31
+ * @example
32
+ * function PlusMinus() {
33
+ * const { isExpanded } = useAccordionItem();
34
+ * return <Icon name={isExpanded ? 'minus' : 'add'} />;
35
+ * }
36
+ */
37
+ export function useAccordionItem(): AccordionItemContextValue {
38
+ const context = useContext(AccordionItemContext);
39
+ if (!context) {
40
+ throw new Error(
41
+ "Accordion.Trigger, Accordion.Indicator and Accordion.Content must be rendered inside <Accordion.Item>."
42
+ );
43
+ }
44
+ return context;
45
+ }
@@ -0,0 +1,51 @@
1
+ import { useCallback, useState } from "react";
2
+
3
+ import type { AccordionProps } from "../types";
4
+
5
+ function toArray(value: string | string[] | null | undefined): string[] {
6
+ if (value == null) return [];
7
+ return Array.isArray(value) ? value : [value];
8
+ }
9
+
10
+ /**
11
+ * Owns which items are open. Both modes are stored as an array so the rest of
12
+ * the accordion never branches on `selectionMode`; the mode only decides what a
13
+ * toggle does and what shape `onValueChange` receives.
14
+ */
15
+ export function useAccordionCore(props: AccordionProps) {
16
+ const isMultiple = props.selectionMode === "multiple";
17
+ const isControlled = props.value !== undefined;
18
+ const isCollapsible = isMultiple || props.isCollapsible !== false;
19
+
20
+ const [internal, setInternal] = useState<string[]>(() => toArray(props.defaultValue));
21
+ const expanded = isControlled ? toArray(props.value) : internal;
22
+
23
+ const { onValueChange } = props;
24
+
25
+ const toggle = useCallback(
26
+ (itemValue: string) => {
27
+ const isOpen = expanded.includes(itemValue);
28
+ let next: string[];
29
+
30
+ if (isMultiple) {
31
+ next = isOpen ? expanded.filter((v) => v !== itemValue) : [...expanded, itemValue];
32
+ } else if (isOpen) {
33
+ if (!isCollapsible) return;
34
+ next = [];
35
+ } else {
36
+ next = [itemValue];
37
+ }
38
+
39
+ if (!isControlled) setInternal(next);
40
+
41
+ if (isMultiple) {
42
+ (onValueChange as ((value: string[]) => void) | undefined)?.(next);
43
+ } else {
44
+ (onValueChange as ((value: string | null) => void) | undefined)?.(next[0] ?? null);
45
+ }
46
+ },
47
+ [expanded, isMultiple, isCollapsible, isControlled, onValueChange]
48
+ );
49
+
50
+ return { expanded, toggle };
51
+ }
@@ -0,0 +1,14 @@
1
+ export { Accordion } from "./Accordion";
2
+ export { useAccordionItem } from "./context";
3
+ export type { AccordionContentProps } from "./parts/AccordionContent";
4
+ export type { AccordionIndicatorProps } from "./parts/AccordionIndicator";
5
+ export type { AccordionItemProps } from "./parts/AccordionItem";
6
+ export type { AccordionTriggerProps } from "./parts/AccordionTrigger";
7
+ export type {
8
+ AccordionItemState,
9
+ AccordionMultipleProps,
10
+ AccordionProps,
11
+ AccordionSelectionMode,
12
+ AccordionSingleProps,
13
+ AccordionVariant,
14
+ } from "./types";
@@ -0,0 +1,96 @@
1
+ import { Children, type ComponentRef, forwardRef, type ReactNode, useEffect, useState } from "react";
2
+ import { type LayoutChangeEvent, View, type ViewProps } from "react-native";
3
+
4
+ import Animated, { useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
5
+ import { StyleSheet } from "react-native-unistyles";
6
+ import { scheduleOnRN } from "react-native-worklets";
7
+
8
+ import { Text } from "../../text";
9
+ import { useAccordionItem } from "../context";
10
+ import { ACCORDION_TIMING } from "../utils";
11
+
12
+ export interface AccordionContentProps extends ViewProps {
13
+ /** The panel body. Strings and numbers are wrapped in body text. */
14
+ children?: ReactNode;
15
+ }
16
+
17
+ function renderBody(children: ReactNode): ReactNode {
18
+ return Children.map(children, (child) => {
19
+ if (typeof child === "string") {
20
+ return child.trim().length > 0 ? (
21
+ <Text variant="body-md" color="text.secondary">
22
+ {child}
23
+ </Text>
24
+ ) : null;
25
+ }
26
+ if (typeof child === "number") {
27
+ return (
28
+ <Text variant="body-md" color="text.secondary">
29
+ {child}
30
+ </Text>
31
+ );
32
+ }
33
+ return child;
34
+ });
35
+ }
36
+
37
+ export const AccordionContent = forwardRef<ComponentRef<typeof View>, AccordionContentProps>(
38
+ function AccordionContent({ children, style, onLayout: onLayoutProp, ...rest }, ref) {
39
+ const { isExpanded } = useAccordionItem();
40
+
41
+ // The body stays mounted while open and while the close animation runs,
42
+ // then unmounts so a long list of closed items costs nothing.
43
+ const [isMounted, setIsMounted] = useState(isExpanded);
44
+ const progress = useSharedValue(isExpanded ? 1 : 0);
45
+ // The body's natural height, read from its own layout. 0 until the first
46
+ // measurement lands.
47
+ const measured = useSharedValue(0);
48
+
49
+ useEffect(() => {
50
+ if (isExpanded) setIsMounted(true);
51
+ progress.value = withTiming(isExpanded ? 1 : 0, ACCORDION_TIMING, (finished) => {
52
+ if (finished && !isExpanded) scheduleOnRN(setIsMounted, false);
53
+ });
54
+ }, [isExpanded, progress]);
55
+
56
+ const onLayout = (event: LayoutChangeEvent) => {
57
+ measured.value = event.nativeEvent.layout.height;
58
+ onLayoutProp?.(event);
59
+ };
60
+
61
+ const clip = useAnimatedStyle(() => {
62
+ // Before the first measurement an item that starts open takes its auto
63
+ // height, and one that is just opening holds at 0 for the frame it takes
64
+ // to measure.
65
+ if (measured.value === 0) {
66
+ return { height: progress.value === 1 ? undefined : 0, opacity: progress.value };
67
+ }
68
+ return { height: measured.value * progress.value, opacity: progress.value };
69
+ });
70
+
71
+ if (!isMounted) return null;
72
+
73
+ return (
74
+ <Animated.View style={[styles.clip, clip]}>
75
+ {/* Not absolutely positioned: RN children do not shrink by default, so
76
+ this keeps its natural height inside the clipping parent and its
77
+ layout reports the height to animate towards. */}
78
+ <View ref={ref} {...rest} onLayout={onLayout} style={[styles.body, style]}>
79
+ {renderBody(children)}
80
+ </View>
81
+ </Animated.View>
82
+ );
83
+ }
84
+ );
85
+
86
+ // ─── Styles ───────────────────────────────────────────────────────────────────
87
+
88
+ const styles = StyleSheet.create((theme) => ({
89
+ clip: {
90
+ overflow: "hidden",
91
+ },
92
+ body: {
93
+ gap: theme.spacing["2"],
94
+ paddingBottom: theme.spacing["4"],
95
+ },
96
+ }));
@@ -0,0 +1,67 @@
1
+ import { type ComponentRef, forwardRef, type ReactNode, useEffect } from "react";
2
+ import type { View, ViewProps } from "react-native";
3
+
4
+ import Animated, { useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
5
+ import { StyleSheet } from "react-native-unistyles";
6
+
7
+ import type { ColorToken } from "#theme/types";
8
+ import { Icon } from "../../icon";
9
+ import { useAccordionItem } from "../context";
10
+ import { ACCORDION_TIMING } from "../utils";
11
+
12
+ export interface AccordionIndicatorProps extends Omit<ViewProps, "children"> {
13
+ /** Chevron color. Ignored with custom `children`. Defaults to `'text.secondary'`. */
14
+ color?: ColorToken;
15
+ /** Chevron size in dp. Ignored with custom `children`. Defaults to `20`. */
16
+ size?: number;
17
+ /**
18
+ * Replaces the chevron. Custom content does not rotate — read `isExpanded`
19
+ * from the item's render function or `useAccordionItem()` to swap it instead.
20
+ */
21
+ children?: ReactNode;
22
+ }
23
+
24
+ export const AccordionIndicator = forwardRef<ComponentRef<typeof View>, AccordionIndicatorProps>(
25
+ function AccordionIndicator({ color = "text.secondary", size = 20, children, style, ...rest }, ref) {
26
+ const { isExpanded } = useAccordionItem();
27
+ // Seeded from the current state so an item that starts open shows its
28
+ // chevron already turned, with no animation on mount.
29
+ const progress = useSharedValue(isExpanded ? 1 : 0);
30
+
31
+ useEffect(() => {
32
+ progress.value = withTiming(isExpanded ? 1 : 0, ACCORDION_TIMING);
33
+ }, [isExpanded, progress]);
34
+
35
+ // `terra.chevron-right` is the chevron the library ships, so it is turned a
36
+ // quarter to point down when closed and a further half to point up when open.
37
+ const rotation = useAnimatedStyle(() => ({
38
+ transform: [{ rotate: `${90 + progress.value * 180}deg` }],
39
+ }));
40
+
41
+ const hasCustomContent = children !== undefined && children !== null;
42
+
43
+ return (
44
+ <Animated.View
45
+ ref={ref}
46
+ accessibilityElementsHidden
47
+ importantForAccessibility="no-hide-descendants"
48
+ style={[styles.indicator, hasCustomContent ? null : rotation, style]}
49
+ {...rest}
50
+ >
51
+ {hasCustomContent ? children : <Icon name="terra.chevron-right" color={color} size={size} />}
52
+ </Animated.View>
53
+ );
54
+ }
55
+ );
56
+
57
+ // ─── Styles ───────────────────────────────────────────────────────────────────
58
+
59
+ const styles = StyleSheet.create(() => ({
60
+ // Pushes the indicator to the row's end even when the title is a custom node
61
+ // that does not take the free space itself.
62
+ indicator: {
63
+ marginStart: "auto",
64
+ alignItems: "center",
65
+ justifyContent: "center",
66
+ },
67
+ }));
@@ -0,0 +1,55 @@
1
+ import { type ComponentRef, forwardRef, type ReactNode, useCallback, useMemo } from "react";
2
+ import { View, type ViewProps } from "react-native";
3
+
4
+ import { StyleSheet } from "react-native-unistyles";
5
+
6
+ import { AccordionItemContext, useAccordionContext } from "../context";
7
+ import type { AccordionItemState } from "../types";
8
+
9
+ export interface AccordionItemProps extends Omit<ViewProps, "children"> {
10
+ /** Identifies the item in the accordion's `value`. Unique within one accordion. */
11
+ value: string;
12
+ /** Disables this item only. Defaults to `false`. */
13
+ isDisabled?: boolean;
14
+ /**
15
+ * The item's trigger and content, or a function that receives the item's
16
+ * `{ isExpanded, isDisabled }` and returns them.
17
+ */
18
+ children?: ReactNode | ((state: AccordionItemState) => ReactNode);
19
+ }
20
+
21
+ export const AccordionItem = forwardRef<ComponentRef<typeof View>, AccordionItemProps>(function AccordionItem(
22
+ { value, isDisabled: isDisabledProp = false, children, style, ...rest },
23
+ ref
24
+ ) {
25
+ const { expanded, toggle: toggleValue, isDisabled: isAccordionDisabled } = useAccordionContext();
26
+
27
+ const isExpanded = expanded.includes(value);
28
+ const isDisabled = isAccordionDisabled || isDisabledProp;
29
+
30
+ const toggle = useCallback(() => {
31
+ if (!isDisabled) toggleValue(value);
32
+ }, [isDisabled, toggleValue, value]);
33
+
34
+ const context = useMemo(
35
+ () => ({ value, isExpanded, isDisabled, toggle }),
36
+ [value, isExpanded, isDisabled, toggle]
37
+ );
38
+
39
+ return (
40
+ <AccordionItemContext.Provider value={context}>
41
+ <View ref={ref} style={[styles.item, style]} {...rest}>
42
+ {typeof children === "function" ? children({ isExpanded, isDisabled }) : children}
43
+ </View>
44
+ </AccordionItemContext.Provider>
45
+ );
46
+ });
47
+
48
+ // ─── Styles ───────────────────────────────────────────────────────────────────
49
+
50
+ // Present so the Unistyles Babel plugin rewrites the `View` above; a themed
51
+ // style passed in through `style` would otherwise freeze at the theme it was
52
+ // created under.
53
+ const styles = StyleSheet.create(() => ({
54
+ item: {},
55
+ }));