@farcaster/snap 2.3.0 → 2.3.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.
package/dist/colors.d.ts CHANGED
@@ -34,6 +34,14 @@ export declare function resolveSnapColorHex(color: string | undefined, opts: {
34
34
  accentHex: string;
35
35
  appearance: "light" | "dark";
36
36
  }): string;
37
+ /**
38
+ * Pick a readable text color for a given hex background.
39
+ *
40
+ * Uses WCAG relative luminance with a 0.5 threshold. Returns `rgba(...)` so
41
+ * callers can soften the text against the background — defaults to 0.8 alpha
42
+ * to let a hint of the cell color bleed through.
43
+ */
44
+ export declare function readableTextOnHex(hex: string, alpha?: number): string;
37
45
  /** Light-mode hex for each palette color (emulator / reference client). */
38
46
  export declare const PALETTE_LIGHT_HEX: Record<PaletteColor, string>;
39
47
  /** Dark-mode hex for each palette color (reference). */
package/dist/colors.js CHANGED
@@ -54,6 +54,27 @@ export function resolveSnapColorHex(color, opts) {
54
54
  }
55
55
  return opts.accentHex;
56
56
  }
57
+ /**
58
+ * Pick a readable text color for a given hex background.
59
+ *
60
+ * Uses WCAG relative luminance with a 0.5 threshold. Returns `rgba(...)` so
61
+ * callers can soften the text against the background — defaults to 0.8 alpha
62
+ * to let a hint of the cell color bleed through.
63
+ */
64
+ export function readableTextOnHex(hex, alpha = 0.8) {
65
+ const m = /^#([0-9a-fA-F]{6})$/.exec(hex.trim());
66
+ if (!m)
67
+ return `rgba(0,0,0,${alpha})`;
68
+ const n = Number.parseInt(m[1], 16);
69
+ const toLin = (c) => {
70
+ const s = c / 255;
71
+ return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
72
+ };
73
+ const L = 0.2126 * toLin((n >> 16) & 0xff) +
74
+ 0.7152 * toLin((n >> 8) & 0xff) +
75
+ 0.0722 * toLin(n & 0xff);
76
+ return L >= 0.5 ? `rgba(0,0,0,${alpha})` : `rgba(255,255,255,${alpha})`;
77
+ }
57
78
  /** Light-mode hex for each palette color (emulator / reference client). */
58
79
  export const PALETTE_LIGHT_HEX = {
59
80
  gray: "#6E6A86",
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export type { Spec as SnapSpec, UIElement as SnapUIElement, } from "@json-render/core";
2
2
  export { SPEC_VERSION, SPEC_VERSION_1, SPEC_VERSION_2, SUPPORTED_SPEC_VERSIONS, type SpecVersion, SNAP_PAYLOAD_HEADER, MEDIA_TYPE, EFFECT_VALUES, POST_GRID_TAP_KEY, MAX_ELEMENTS, MAX_ROOT_CHILDREN, MAX_CHILDREN, MAX_DEPTH, } from "./constants.js";
3
- export { DEFAULT_THEME_ACCENT, PALETTE_COLOR, PALETTE_COLOR_ACCENT, PALETTE_COLOR_VALUES, PALETTE_LIGHT_HEX, PALETTE_DARK_HEX, isSnapHexColorString, resolveSnapColorHex, type PaletteColor, } from "./colors.js";
3
+ export { DEFAULT_THEME_ACCENT, PALETTE_COLOR, PALETTE_COLOR_ACCENT, PALETTE_COLOR_VALUES, PALETTE_LIGHT_HEX, PALETTE_DARK_HEX, isSnapHexColorString, readableTextOnHex, resolveSnapColorHex, type PaletteColor, } from "./colors.js";
4
4
  export { ACTION_TYPE_GET, ACTION_TYPE_POST, snapResponseSchema, payloadSchema, getPayloadSchema, type SnapAction, type SnapGetAction, type SnapContext, type SnapResponse, type SnapHandlerResult, type SnapElementInput, type SnapSpecInput, type SnapFunction, type SnapPayload, type SnapGetPayload, } from "./schemas.js";
5
5
  export { validateSnapResponse, type ValidationResult } from "./validator.js";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export { SPEC_VERSION, SPEC_VERSION_1, SPEC_VERSION_2, SUPPORTED_SPEC_VERSIONS, SNAP_PAYLOAD_HEADER, MEDIA_TYPE, EFFECT_VALUES, POST_GRID_TAP_KEY, MAX_ELEMENTS, MAX_ROOT_CHILDREN, MAX_CHILDREN, MAX_DEPTH, } from "./constants.js";
2
- export { DEFAULT_THEME_ACCENT, PALETTE_COLOR, PALETTE_COLOR_ACCENT, PALETTE_COLOR_VALUES, PALETTE_LIGHT_HEX, PALETTE_DARK_HEX, isSnapHexColorString, resolveSnapColorHex, } from "./colors.js";
2
+ export { DEFAULT_THEME_ACCENT, PALETTE_COLOR, PALETTE_COLOR_ACCENT, PALETTE_COLOR_VALUES, PALETTE_LIGHT_HEX, PALETTE_DARK_HEX, isSnapHexColorString, readableTextOnHex, resolveSnapColorHex, } from "./colors.js";
3
3
  export { ACTION_TYPE_GET, ACTION_TYPE_POST, snapResponseSchema, payloadSchema, getPayloadSchema, } from "./schemas.js";
4
4
  export { validateSnapResponse } from "./validator.js";
@@ -5,6 +5,7 @@ import { ExternalLink } from "lucide-react";
5
5
  import { Button } from "@neynar/ui/button";
6
6
  import { cn } from "@neynar/ui/utils";
7
7
  import { useSnapColors } from "../hooks/use-snap-colors.js";
8
+ import { useSnapStackDirection } from "../stack-direction-context.js";
8
9
  import { ICON_MAP } from "./icon.js";
9
10
  function isExternalLinkAction(on) {
10
11
  if (!on)
@@ -24,6 +25,7 @@ export function SnapActionButton({ element, emit, }) {
24
25
  const [hovered, setHovered] = useState(false);
25
26
  const Icon = iconName ? ICON_MAP[iconName] : undefined;
26
27
  const showExternalIcon = isExternalLinkAction(element.on);
28
+ const inHorizontalStack = useSnapStackDirection() === "horizontal";
27
29
  const style = {
28
30
  cursor: "pointer",
29
31
  ...(isPrimary
@@ -40,5 +42,13 @@ export function SnapActionButton({ element, emit, }) {
40
42
  borderColor: "transparent",
41
43
  }),
42
44
  };
43
- return (_jsx("div", { className: "w-full min-w-0 flex-1", children: _jsxs(Button, { type: "button", variant: isPrimary ? "default" : "secondary", className: cn("w-full gap-2"), style: style, onClick: () => emit("press"), onPointerEnter: () => setHovered(true), onPointerLeave: () => setHovered(false), children: [Icon && _jsx(Icon, { size: 16 }), label, showExternalIcon && (_jsx(ExternalLink, { size: 14, style: { opacity: 0.6 } }))] }) }));
45
+ return (
46
+ /**
47
+ * In a horizontal stack, `flex-1` lets the wrapper share row width with peers.
48
+ * In a vertical stack, `flex-1` would silently grow the button to fill column
49
+ * height (1/N distribution when siblings also flex-grow); stick to `w-full`.
50
+ */
51
+ _jsx("div", { className: inHorizontalStack
52
+ ? "w-full min-w-0 flex-1"
53
+ : "w-full min-w-0", children: _jsxs(Button, { type: "button", variant: isPrimary ? "default" : "secondary", className: cn("w-full gap-2"), style: style, onClick: () => emit("press"), onPointerEnter: () => setHovered(true), onPointerLeave: () => setHovered(false), children: [Icon && _jsx(Icon, { size: 16 }), label, showExternalIcon && (_jsx(ExternalLink, { size: 14, style: { opacity: 0.6 } }))] }) }));
44
54
  }
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { useStateStore } from "@json-render/react";
4
4
  import { cn } from "@neynar/ui/utils";
5
- import { POST_GRID_TAP_KEY } from "@farcaster/snap";
5
+ import { POST_GRID_TAP_KEY, readableTextOnHex } from "@farcaster/snap";
6
6
  import { useSnapColors } from "../hooks/use-snap-colors.js";
7
7
  export function SnapCellGrid({ element: { props, on }, emit, }) {
8
8
  const { get, set } = useStateStore();
@@ -69,7 +69,9 @@ export function SnapCellGrid({ element: { props, on }, emit, }) {
69
69
  for (let c = 0; c < cols; c++) {
70
70
  const cell = cellMap.get(`${r},${c}`);
71
71
  const selected = interactive && isSelected(r, c);
72
- const bg = cell?.color ? colors.colorHex(cell.color) : emptyCellBg;
72
+ const bgHex = cell?.color ? colors.colorHex(cell.color) : null;
73
+ const bg = bgHex ?? emptyCellBg;
74
+ const textColor = bgHex ? readableTextOnHex(bgHex) : colors.text;
73
75
  cellEls.push(_jsx("div", { role: interactive ? "button" : undefined, tabIndex: interactive ? 0 : undefined, onClick: interactive ? () => handleTap(r, c) : undefined, onKeyDown: interactive
74
76
  ? (e) => {
75
77
  if (e.key === "Enter" || e.key === " ") {
@@ -80,6 +82,7 @@ export function SnapCellGrid({ element: { props, on }, emit, }) {
80
82
  : undefined, className: cn("flex items-center justify-center rounded text-xs font-semibold", interactive ? "cursor-pointer select-none" : "cursor-default"), style: {
81
83
  height: rowHeight,
82
84
  background: bg,
85
+ color: textColor,
83
86
  boxShadow: selected
84
87
  ? `inset 0 0 0 1px ${colors.mode === "dark" ? "#000" : "#fff"}, inset 0 0 0 2px ${colors.mode === "dark" ? "#fff" : "#000"}`
85
88
  : undefined,
@@ -1,10 +1,15 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Item, ItemContent, ItemTitle, ItemDescription, ItemActions, } from "@neynar/ui/item";
4
+ import { cn } from "@neynar/ui/utils";
4
5
  import { useSnapColors } from "../hooks/use-snap-colors.js";
6
+ import { useSnapStackDirection } from "../stack-direction-context.js";
5
7
  export function SnapItem({ element: { props, children: childIds }, children, }) {
6
8
  const title = String(props.title ?? "");
7
9
  const description = props.description ? String(props.description) : undefined;
8
10
  const colors = useSnapColors();
9
- return (_jsxs(Item, { className: "flex-1 py-1.5 px-2.5", children: [_jsxs(ItemContent, { className: "gap-0.5", children: [_jsx(ItemTitle, { style: { color: colors.text }, children: title }), description && (_jsx(ItemDescription, { className: "mt-0", style: { color: colors.textMuted }, children: description }))] }), childIds && childIds.length > 0 && _jsx(ItemActions, { children: children })] }));
11
+ const inHorizontalStack = useSnapStackDirection() === "horizontal";
12
+ return (_jsxs(Item, { className: cn("py-1.5 px-2.5",
13
+ /** Horizontal: share width with peers. Vertical: don't fill column height. */
14
+ inHorizontalStack && "flex-1"), children: [_jsxs(ItemContent, { className: "gap-0.5", children: [_jsx(ItemTitle, { style: { color: colors.text }, children: title }), description && (_jsx(ItemDescription, { className: "mt-0", style: { color: colors.textMuted }, children: description }))] }), childIds && childIds.length > 0 && _jsx(ItemActions, { children: children })] }));
10
15
  }
@@ -1,11 +1,16 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { cn } from "@neynar/ui/utils";
3
4
  import { useSnapColors } from "../hooks/use-snap-colors.js";
5
+ import { useSnapStackDirection } from "../stack-direction-context.js";
4
6
  export function SnapProgress({ element: { props }, }) {
5
7
  const colors = useSnapColors();
6
8
  const value = Number(props.value ?? 0);
7
9
  const max = Math.max(1, Number(props.max ?? 100));
8
10
  const percent = Math.min(100, Math.max(0, (value / max) * 100));
9
11
  const label = props.label ? String(props.label) : null;
10
- return (_jsxs("div", { className: "flex w-full flex-1 flex-col gap-1", children: [label && (_jsx("span", { className: "text-xs", style: { color: colors.textMuted }, children: label })), _jsx("div", { className: "h-2.5 w-full overflow-hidden rounded-full", style: { backgroundColor: colors.muted }, children: _jsx("div", { className: "h-full rounded-full transition-all", style: { width: `${percent}%`, backgroundColor: colors.accent } }) })] }));
12
+ const inHorizontalStack = useSnapStackDirection() === "horizontal";
13
+ return (_jsxs("div", { className: cn("flex w-full flex-col gap-1",
14
+ /** Horizontal: share width with peers. Vertical: don't fill column height. */
15
+ inHorizontalStack && "flex-1"), children: [label && (_jsx("span", { className: "text-xs", style: { color: colors.textMuted }, children: label })), _jsx("div", { className: "h-2.5 w-full overflow-hidden rounded-full", style: { backgroundColor: colors.muted }, children: _jsx("div", { className: "h-full rounded-full transition-all", style: { width: `${percent}%`, backgroundColor: colors.accent } }) })] }));
11
16
  }
@@ -3,7 +3,7 @@ import { StyleSheet, Text, View, Pressable } from "react-native";
3
3
  import { useStateStore } from "@json-render/react-native";
4
4
  import { useSnapPalette } from "../use-snap-palette.js";
5
5
  import { useSnapTheme } from "../theme.js";
6
- import { POST_GRID_TAP_KEY } from "@farcaster/snap";
6
+ import { POST_GRID_TAP_KEY, readableTextOnHex } from "@farcaster/snap";
7
7
  export function SnapCellGrid({ element, emit, }) {
8
8
  const { props } = element;
9
9
  const on = element.on;
@@ -75,8 +75,10 @@ export function SnapCellGrid({ element, emit, }) {
75
75
  for (let c = 0; c < cols; c++) {
76
76
  const cell = cellMap.get(`${r},${c}`);
77
77
  const selected = interactive && isSelected(r, c);
78
- const bg = cell?.color ? hex(cell.color) : emptyCellBg;
79
- const cellContent = cell?.content ? (_jsx(Text, { style: [styles.cellText, { color: colors.textPrimary }], children: cell.content })) : null;
78
+ const bgHex = cell?.color ? hex(cell.color) : null;
79
+ const bg = bgHex ?? emptyCellBg;
80
+ const textColor = bgHex ? readableTextOnHex(bgHex) : colors.text;
81
+ const cellContent = cell?.content ? (_jsx(Text, { style: [styles.cellText, { color: textColor }], children: cell.content })) : null;
80
82
  // Two-tone ring: outer View with contrasting border, inner View with inverse border
81
83
  const cellView = selected ? (_jsx(View, { style: [styles.cell, { height: rowHeight, borderWidth: 1, borderColor: ringOuter, borderRadius: 4 }], children: _jsx(View, { style: [
82
84
  styles.innerCell,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farcaster/snap",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "description": "Farcaster Snaps 🫰",
5
5
  "repository": {
6
6
  "type": "git",
package/src/colors.ts CHANGED
@@ -65,6 +65,28 @@ export function resolveSnapColorHex(
65
65
  return opts.accentHex;
66
66
  }
67
67
 
68
+ /**
69
+ * Pick a readable text color for a given hex background.
70
+ *
71
+ * Uses WCAG relative luminance with a 0.5 threshold. Returns `rgba(...)` so
72
+ * callers can soften the text against the background — defaults to 0.8 alpha
73
+ * to let a hint of the cell color bleed through.
74
+ */
75
+ export function readableTextOnHex(hex: string, alpha = 0.8): string {
76
+ const m = /^#([0-9a-fA-F]{6})$/.exec(hex.trim());
77
+ if (!m) return `rgba(0,0,0,${alpha})`;
78
+ const n = Number.parseInt(m[1], 16);
79
+ const toLin = (c: number) => {
80
+ const s = c / 255;
81
+ return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
82
+ };
83
+ const L =
84
+ 0.2126 * toLin((n >> 16) & 0xff) +
85
+ 0.7152 * toLin((n >> 8) & 0xff) +
86
+ 0.0722 * toLin(n & 0xff);
87
+ return L >= 0.5 ? `rgba(0,0,0,${alpha})` : `rgba(255,255,255,${alpha})`;
88
+ }
89
+
68
90
  /** Light-mode hex for each palette color (emulator / reference client). */
69
91
  export const PALETTE_LIGHT_HEX: Record<PaletteColor, string> = {
70
92
  gray: "#6E6A86",
package/src/index.ts CHANGED
@@ -25,6 +25,7 @@ export {
25
25
  PALETTE_LIGHT_HEX,
26
26
  PALETTE_DARK_HEX,
27
27
  isSnapHexColorString,
28
+ readableTextOnHex,
28
29
  resolveSnapColorHex,
29
30
  type PaletteColor,
30
31
  } from "./colors";
@@ -5,6 +5,7 @@ import { ExternalLink } from "lucide-react";
5
5
  import { Button } from "@neynar/ui/button";
6
6
  import { cn } from "@neynar/ui/utils";
7
7
  import { useSnapColors } from "../hooks/use-snap-colors";
8
+ import { useSnapStackDirection } from "../stack-direction-context";
8
9
  import { ICON_MAP } from "./icon";
9
10
 
10
11
  function isExternalLinkAction(
@@ -38,6 +39,7 @@ export function SnapActionButton({
38
39
 
39
40
  const Icon = iconName ? ICON_MAP[iconName] : undefined;
40
41
  const showExternalIcon = isExternalLinkAction(element.on);
42
+ const inHorizontalStack = useSnapStackDirection() === "horizontal";
41
43
 
42
44
  const style = {
43
45
  cursor: "pointer" as const,
@@ -57,7 +59,18 @@ export function SnapActionButton({
57
59
  };
58
60
 
59
61
  return (
60
- <div className="w-full min-w-0 flex-1">
62
+ /**
63
+ * In a horizontal stack, `flex-1` lets the wrapper share row width with peers.
64
+ * In a vertical stack, `flex-1` would silently grow the button to fill column
65
+ * height (1/N distribution when siblings also flex-grow); stick to `w-full`.
66
+ */
67
+ <div
68
+ className={
69
+ inHorizontalStack
70
+ ? "w-full min-w-0 flex-1"
71
+ : "w-full min-w-0"
72
+ }
73
+ >
61
74
  <Button
62
75
  type="button"
63
76
  variant={isPrimary ? "default" : "secondary"}
@@ -3,7 +3,7 @@
3
3
  import type { ReactNode } from "react";
4
4
  import { useStateStore } from "@json-render/react";
5
5
  import { cn } from "@neynar/ui/utils";
6
- import { POST_GRID_TAP_KEY } from "@farcaster/snap";
6
+ import { POST_GRID_TAP_KEY, readableTextOnHex } from "@farcaster/snap";
7
7
  import { useSnapColors } from "../hooks/use-snap-colors";
8
8
 
9
9
  export function SnapCellGrid({
@@ -85,7 +85,9 @@ export function SnapCellGrid({
85
85
  for (let c = 0; c < cols; c++) {
86
86
  const cell = cellMap.get(`${r},${c}`);
87
87
  const selected = interactive && isSelected(r, c);
88
- const bg = cell?.color ? colors.colorHex(cell.color) : emptyCellBg;
88
+ const bgHex = cell?.color ? colors.colorHex(cell.color) : null;
89
+ const bg = bgHex ?? emptyCellBg;
90
+ const textColor = bgHex ? readableTextOnHex(bgHex) : colors.text;
89
91
 
90
92
  cellEls.push(
91
93
  <div
@@ -110,6 +112,7 @@ export function SnapCellGrid({
110
112
  style={{
111
113
  height: rowHeight,
112
114
  background: bg,
115
+ color: textColor,
113
116
  boxShadow: selected
114
117
  ? `inset 0 0 0 1px ${colors.mode === "dark" ? "#000" : "#fff"}, inset 0 0 0 2px ${colors.mode === "dark" ? "#fff" : "#000"}`
115
118
  : undefined,
@@ -7,7 +7,9 @@ import {
7
7
  ItemDescription,
8
8
  ItemActions,
9
9
  } from "@neynar/ui/item";
10
+ import { cn } from "@neynar/ui/utils";
10
11
  import { useSnapColors } from "../hooks/use-snap-colors";
12
+ import { useSnapStackDirection } from "../stack-direction-context";
11
13
 
12
14
  export function SnapItem({
13
15
  element: { props, children: childIds },
@@ -19,9 +21,16 @@ export function SnapItem({
19
21
  const title = String(props.title ?? "");
20
22
  const description = props.description ? String(props.description) : undefined;
21
23
  const colors = useSnapColors();
24
+ const inHorizontalStack = useSnapStackDirection() === "horizontal";
22
25
 
23
26
  return (
24
- <Item className="flex-1 py-1.5 px-2.5">
27
+ <Item
28
+ className={cn(
29
+ "py-1.5 px-2.5",
30
+ /** Horizontal: share width with peers. Vertical: don't fill column height. */
31
+ inHorizontalStack && "flex-1",
32
+ )}
33
+ >
25
34
  <ItemContent className="gap-0.5">
26
35
  <ItemTitle style={{ color: colors.text }}>{title}</ItemTitle>
27
36
  {description && (
@@ -1,6 +1,8 @@
1
1
  "use client";
2
2
 
3
+ import { cn } from "@neynar/ui/utils";
3
4
  import { useSnapColors } from "../hooks/use-snap-colors";
5
+ import { useSnapStackDirection } from "../stack-direction-context";
4
6
 
5
7
  export function SnapProgress({
6
8
  element: { props },
@@ -12,9 +14,16 @@ export function SnapProgress({
12
14
  const max = Math.max(1, Number(props.max ?? 100));
13
15
  const percent = Math.min(100, Math.max(0, (value / max) * 100));
14
16
  const label = props.label ? String(props.label) : null;
17
+ const inHorizontalStack = useSnapStackDirection() === "horizontal";
15
18
 
16
19
  return (
17
- <div className="flex w-full flex-1 flex-col gap-1">
20
+ <div
21
+ className={cn(
22
+ "flex w-full flex-col gap-1",
23
+ /** Horizontal: share width with peers. Vertical: don't fill column height. */
24
+ inHorizontalStack && "flex-1",
25
+ )}
26
+ >
18
27
  {label && (
19
28
  <span className="text-xs" style={{ color: colors.textMuted }}>
20
29
  {label}
@@ -3,7 +3,7 @@ import { StyleSheet, Text, View, Pressable } from "react-native";
3
3
  import { useStateStore } from "@json-render/react-native";
4
4
  import { useSnapPalette } from "../use-snap-palette";
5
5
  import { useSnapTheme } from "../theme";
6
- import { POST_GRID_TAP_KEY } from "@farcaster/snap";
6
+ import { POST_GRID_TAP_KEY, readableTextOnHex } from "@farcaster/snap";
7
7
 
8
8
  export function SnapCellGrid({
9
9
  element,
@@ -89,10 +89,12 @@ export function SnapCellGrid({
89
89
  for (let c = 0; c < cols; c++) {
90
90
  const cell = cellMap.get(`${r},${c}`);
91
91
  const selected = interactive && isSelected(r, c);
92
- const bg = cell?.color ? hex(cell.color) : emptyCellBg;
92
+ const bgHex = cell?.color ? hex(cell.color) : null;
93
+ const bg = bgHex ?? emptyCellBg;
94
+ const textColor = bgHex ? readableTextOnHex(bgHex) : colors.text;
93
95
 
94
96
  const cellContent = cell?.content ? (
95
- <Text style={[styles.cellText, { color: colors.textPrimary }]}>
97
+ <Text style={[styles.cellText, { color: textColor }]}>
96
98
  {cell.content}
97
99
  </Text>
98
100
  ) : null;