@vvedantb/native-ui 0.17.2 → 0.18.0
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/AlertDialog.jsx +123 -0
- package/dist/AmbientBackground.jsx +73 -0
- package/dist/ArtifactList.jsx +59 -0
- package/dist/Avatar.jsx +285 -0
- package/dist/Badge.jsx +154 -0
- package/dist/BottomSheetContainer.jsx +208 -0
- package/dist/BulkActionBar.jsx +717 -0
- package/dist/Button.jsx +344 -0
- package/dist/CaptureButton.jsx +104 -0
- package/dist/Card.jsx +371 -0
- package/dist/Checkbox.jsx +177 -0
- package/dist/Chip.jsx +79 -0
- package/dist/ColorSwatches.jsx +159 -0
- package/dist/ConfirmDialog.jsx +157 -0
- package/dist/DateTimeField.jsx +204 -0
- package/dist/Dialog.jsx +614 -0
- package/dist/DividedList.jsx +120 -0
- package/dist/DropdownMenu.jsx +849 -0
- package/dist/EmptyState.jsx +434 -0
- package/dist/ExpoWebRoot.jsx +134 -0
- package/dist/FloatingFAB.jsx +95 -0
- package/dist/FloatingSurface.jsx +226 -0
- package/dist/FloatingTabBar.jsx +403 -0
- package/dist/HeaderIconButton.jsx +53 -0
- package/dist/IconButton.jsx +157 -0
- package/dist/Input.jsx +96 -0
- package/dist/Label.jsx +96 -0
- package/dist/LabeledSwitchRow.jsx +170 -0
- package/dist/LiquidGlass.jsx +2 -0
- package/dist/ListRow.jsx +281 -0
- package/dist/LoadingState.jsx +205 -0
- package/dist/PageIndicator.jsx +128 -0
- package/dist/PageTitle.jsx +205 -0
- package/dist/Pager.jsx +105 -0
- package/dist/PasswordInput.jsx +120 -0
- package/dist/PillTabs.jsx +300 -0
- package/dist/PinnedBotTile.jsx +212 -0
- package/dist/Progress.jsx +147 -0
- package/dist/SafeAreaContainer.jsx +38 -0
- package/dist/ScreenContainer.jsx +117 -0
- package/dist/SearchInput.jsx +150 -0
- package/dist/SectionLabel.jsx +128 -0
- package/dist/Select.jsx +223 -0
- package/dist/Separator.jsx +95 -0
- package/dist/Sheet.jsx +343 -0
- package/dist/SheetRow.jsx +198 -0
- package/dist/Skeleton.jsx +311 -0
- package/dist/Spinner.jsx +195 -0
- package/dist/StackPageHeader.jsx +160 -0
- package/dist/StatGrid.jsx +74 -0
- package/dist/StatusDot.jsx +129 -0
- package/dist/SurfaceRow.jsx +143 -0
- package/dist/SwipeableRow.jsx +50 -0
- package/dist/Switch.jsx +130 -0
- package/dist/Tabs.jsx +385 -0
- package/dist/Textarea.jsx +103 -0
- package/dist/ThemeToggle.jsx +78 -0
- package/dist/Toast.jsx +396 -0
- package/dist/ai/activity-step-detail.jsx +179 -0
- package/dist/ai/activity-step-label.js +816 -0
- package/dist/ai/activity-step-types.js +14 -0
- package/dist/ai/activity-step.jsx +98 -0
- package/dist/ai/activity-tasks-utils.js +172 -0
- package/dist/ai/activity-timeline.js +47 -0
- package/dist/ai/attachments.jsx +258 -0
- package/dist/ai/card-button.jsx +188 -0
- package/dist/ai/chain-of-thought.jsx +459 -0
- package/dist/ai/chat-jump-rail.jsx +57 -0
- package/dist/ai/chat-text.js +44 -0
- package/dist/ai/chat-thread.jsx +135 -0
- package/dist/ai/choice-question.jsx +925 -0
- package/dist/ai/code-block.jsx +574 -0
- package/dist/ai/collapsible.jsx +275 -0
- package/dist/ai/conversation.jsx +723 -0
- package/dist/ai/file-chip.jsx +198 -0
- package/dist/ai/icon-button.jsx +179 -0
- package/dist/ai/index.js +37 -0
- package/dist/ai/message-action-sheet.jsx +408 -0
- package/dist/ai/message-quote.jsx +241 -0
- package/dist/ai/message.jsx +739 -0
- package/dist/ai/prompt-input-menu.jsx +365 -0
- package/dist/ai/prompt-input.jsx +626 -0
- package/dist/ai/reasoning.jsx +446 -0
- package/dist/ai/reply-quote-chip.jsx +278 -0
- package/dist/ai/response-text.jsx +130 -0
- package/dist/ai/shimmer.jsx +149 -0
- package/dist/ai/sources.jsx +260 -0
- package/dist/ai/subagent-cards.jsx +645 -0
- package/dist/ai/suggestion.jsx +186 -0
- package/dist/ai/tool-approval-card.jsx +359 -0
- package/dist/ai/trace.jsx +728 -0
- package/dist/ai/unified-diff.jsx +280 -0
- package/dist/ai/use-streaming-disclosure.js +70 -0
- package/dist/auth/AuthProviders.jsx +27 -0
- package/dist/auth/AuthScreen.jsx +292 -0
- package/dist/auth/GoogleSignInButton.jsx +188 -0
- package/dist/auth/SecondFactorScreen.jsx +133 -0
- package/dist/auth/SignInScreen.jsx +482 -0
- package/dist/auth/authErrors.js +131 -0
- package/dist/auth/index.js +11 -0
- package/dist/auth/totp.js +378 -0
- package/dist/blur.js +36 -0
- package/dist/brand/AppIcons.jsx +118 -0
- package/dist/brand/AppMark.jsx +128 -0
- package/dist/brand/AppWordmark.jsx +138 -0
- package/dist/brand/GoogleMark.jsx +71 -0
- package/dist/brand/ProviderIcon.jsx +192 -0
- package/dist/brand/familyApps.js +33 -0
- package/dist/brand/index.js +11 -0
- package/dist/brand/svg.js +252 -0
- package/dist/brand/vProAppBenefits.js +19 -0
- package/dist/cn.js +5 -0
- package/dist/colors.js +15 -0
- package/dist/configureTheme.js +72 -0
- package/dist/controlStyles.js +520 -0
- package/dist/definiteSize.js +12 -0
- package/dist/dialogLayout.js +18 -0
- package/dist/entries/ai.js +4 -0
- package/dist/entries/ambient.js +3 -0
- package/dist/entries/auth.js +5 -0
- package/dist/entries/bottom-sheet.js +2 -0
- package/dist/entries/brand.js +2 -0
- package/dist/entries/button.js +2 -0
- package/dist/entries/date-time.js +3 -0
- package/dist/entries/expo-router.js +4 -0
- package/dist/entries/expo-web-root.js +3 -0
- package/dist/entries/floating.js +7 -0
- package/dist/entries/gesture-handler.js +4 -0
- package/dist/entries/keyboard-controller.js +4 -0
- package/dist/entries/layout.js +16 -0
- package/dist/entries/markdown.js +4 -0
- package/dist/entries/marketing.js +3 -0
- package/dist/entries/page-title.js +7 -0
- package/dist/entries/password-input.js +3 -0
- package/dist/entries/primitives.js +57 -0
- package/dist/entries/search-input.js +3 -0
- package/dist/entries/tab-bar.js +4 -0
- package/dist/entries/theme.js +7 -0
- package/dist/entries/toast.js +5 -0
- package/dist/entries/video.js +3 -0
- package/dist/entries/webview.js +4 -0
- package/dist/examples/AiChatGallery.jsx +509 -0
- package/dist/examples/ParityGallery.jsx +1307 -0
- package/dist/floating.js +62 -0
- package/dist/glassBlur.jsx +145 -0
- package/dist/gradient.js +17 -0
- package/dist/haptics.js +44 -0
- package/dist/highlight.js +382 -0
- package/dist/index.js +85 -0
- package/dist/initials.js +4 -0
- package/dist/loadingGrid.js +81 -0
- package/dist/markdown/Markdown.jsx +515 -0
- package/dist/markdown/MarkdownTable.jsx +443 -0
- package/dist/markdown/tableText.js +68 -0
- package/dist/marketing/PricingModal.jsx +608 -0
- package/dist/marketing/UpgradeToProCard.jsx +164 -0
- package/dist/marketing/pricing.js +34 -0
- package/dist/media/ImageGallery.jsx +580 -0
- package/dist/media/MediaCard.jsx +162 -0
- package/dist/media/imageGrid.js +54 -0
- package/dist/motion.js +33 -0
- package/dist/pagerSwipe.js +104 -0
- package/dist/palette.js +104 -0
- package/dist/primitives/button.jsx +127 -0
- package/dist/primitives/card.jsx +249 -0
- package/dist/primitives/icon.jsx +37 -0
- package/dist/primitives/input.jsx +56 -0
- package/dist/primitives/keyboard-controller.jsx +207 -0
- package/dist/primitives/keyboard-parts.jsx +75 -0
- package/dist/primitives/native-only-animated-view.jsx +68 -0
- package/dist/primitives/overlay.jsx +391 -0
- package/dist/primitives/pager-gesture.jsx +131 -0
- package/dist/primitives/select-host.jsx +103 -0
- package/dist/primitives/select.jsx +555 -0
- package/dist/primitives/sheet-drag.jsx +420 -0
- package/dist/primitives/sheet-gesture.jsx +219 -0
- package/dist/primitives/swipe-row-gesture.jsx +341 -0
- package/dist/primitives/switch.jsx +105 -0
- package/dist/primitives/text.jsx +145 -0
- package/dist/primitives/toast-drag-gesture.jsx +94 -0
- package/dist/primitives/use-controllable-state.js +40 -0
- package/dist/primitives/web-click-guard.js +69 -0
- package/dist/push.js +166 -0
- package/dist/relativeTime.js +70 -0
- package/dist/router/RouterStackPageHeader.jsx +53 -0
- package/dist/selectA11y.js +32 -0
- package/dist/settings/MoreFromProjectV.jsx +168 -0
- package/dist/settings/SettingsEmptyState.jsx +102 -0
- package/dist/settings/SettingsField.jsx +49 -0
- package/dist/settings/SettingsSection.jsx +101 -0
- package/dist/settings/SettingsStack.jsx +17 -0
- package/dist/settings/SettingsToggleRow.jsx +163 -0
- package/dist/settings/projectVMobileApps.js +126 -0
- package/dist/settings/relaxedSizeStyle.js +11 -0
- package/dist/sheetDrag.js +76 -0
- package/dist/svgA11y.js +46 -0
- package/dist/swipeRow.js +161 -0
- package/dist/tabBarRoutes.js +41 -0
- package/dist/tabIndicator.js +139 -0
- package/dist/tailwind-preset.cjs +255 -0
- package/dist/tailwind-preset.d.cts +55 -0
- package/dist/theme.jsx +62 -0
- package/dist/toastChrome.js +110 -0
- package/dist/toastDrag.js +51 -0
- package/dist/toastStore.js +54 -0
- package/dist/tokens.js +70 -0
- package/dist/typography.js +40 -0
- package/dist/useReduceMotion.js +32 -0
- package/dist/useReduceTransparency.js +27 -0
- package/dist/useScheme.js +15 -0
- package/dist/video/InlineVideo.jsx +115 -0
- package/dist/webview/HtmlView.jsx +169 -0
- package/dist/webview/HtmlView.web.jsx +63 -0
- package/dist/webview/htmlView.js +43 -0
- package/package.json +70 -33
- package/src/DropdownMenu.tsx +28 -16
- package/src/FloatingTabBar.tsx +78 -41
- package/src/ai/conversation.tsx +12 -8
- package/src/glassBlur.tsx +47 -22
- package/src/primitives/swipe-row-gesture.tsx +11 -2
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
import { c as _c } from "react/compiler-runtime";
|
|
2
|
+
import { useContext, useState } from "react";
|
|
3
|
+
import { Platform, Pressable, Text, View, useWindowDimensions } from "react-native";
|
|
4
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
5
|
+
import { IconArrowUp, IconChevronDown, IconPlayerStopFilled } from "@tabler/icons-react-native";
|
|
6
|
+
import { cn } from "../cn";
|
|
7
|
+
import { MIN_TOUCH_TARGET, fieldStyle, fieldTextStyle, sizeStyle, touchSlop, typeStyle } from "../controlStyles";
|
|
8
|
+
import { withAlpha } from "../palette";
|
|
9
|
+
import { tokens } from "../tokens";
|
|
10
|
+
import { Input as FieldInput } from "../primitives/input";
|
|
11
|
+
import { COMPOSER_INPUT_ID, KeyboardAvoidingView, KeyboardLiftContext } from "../primitives/keyboard-parts";
|
|
12
|
+
import { usePressFeedback } from "../motion";
|
|
13
|
+
import { useControllableState } from "../primitives/use-controllable-state";
|
|
14
|
+
import { useLargerText } from "../theme";
|
|
15
|
+
import { useScheme } from "../useScheme";
|
|
16
|
+
import { ChatIconButton } from "./icon-button";
|
|
17
|
+
|
|
18
|
+
/** The `ai` SDK chat status the web `PromptInputSubmit` takes. */
|
|
19
|
+
|
|
20
|
+
/** Whether the AI is answering: `submitted` (waiting) or `streaming`. */
|
|
21
|
+
export function isGenerating(status) {
|
|
22
|
+
return status === "submitted" || status === "streaming";
|
|
23
|
+
}
|
|
24
|
+
// The web `PromptInputSubmit` and `PromptInputButton` keep `shape="rounded"`
|
|
25
|
+
// (`rounded-lg`, 16) as field addons. At the 32 `icon-sm` size 16 is half the
|
|
26
|
+
// side, so the web draws a circle. These stay pills: the same circle at 32, and
|
|
27
|
+
// still a circle at 44 with larger text, where 16 would draw a rounded square.
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Send, or stop while the AI answers: the web `default` `icon-sm` button
|
|
31
|
+
* (32, round, slop to 44). Send is an up arrow on the primary fill, faded by
|
|
32
|
+
* the disabled `Button` with nothing to send, as the web send button. While
|
|
33
|
+
* `status` is `submitted` or `streaming` it is a filled square labelled
|
|
34
|
+
* "Stop" that calls `onStop` (disabled without one).
|
|
35
|
+
*/
|
|
36
|
+
export function PromptInputSubmit(t0) {
|
|
37
|
+
const $ = _c(10);
|
|
38
|
+
const {
|
|
39
|
+
status,
|
|
40
|
+
onSubmit,
|
|
41
|
+
onStop,
|
|
42
|
+
canSubmit: t1,
|
|
43
|
+
size,
|
|
44
|
+
testID
|
|
45
|
+
} = t0;
|
|
46
|
+
const canSubmit = t1 === undefined ? true : t1;
|
|
47
|
+
if (isGenerating(status)) {
|
|
48
|
+
const t2 = !onStop;
|
|
49
|
+
let t3;
|
|
50
|
+
if ($[0] !== onStop || $[1] !== size || $[2] !== t2 || $[3] !== testID) {
|
|
51
|
+
t3 = <ChatIconButton icon={IconPlayerStopFilled} label="Stop" variant="primary" size={size} onPress={onStop} disabled={t2} testID={testID} />;
|
|
52
|
+
$[0] = onStop;
|
|
53
|
+
$[1] = size;
|
|
54
|
+
$[2] = t2;
|
|
55
|
+
$[3] = testID;
|
|
56
|
+
$[4] = t3;
|
|
57
|
+
} else {
|
|
58
|
+
t3 = $[4];
|
|
59
|
+
}
|
|
60
|
+
return t3;
|
|
61
|
+
}
|
|
62
|
+
const t2 = !canSubmit;
|
|
63
|
+
let t3;
|
|
64
|
+
if ($[5] !== onSubmit || $[6] !== size || $[7] !== t2 || $[8] !== testID) {
|
|
65
|
+
t3 = <ChatIconButton icon={IconArrowUp} label="Send" variant="primary" size={size} onPress={onSubmit} disabled={t2} testID={testID} />;
|
|
66
|
+
$[5] = onSubmit;
|
|
67
|
+
$[6] = size;
|
|
68
|
+
$[7] = t2;
|
|
69
|
+
$[8] = testID;
|
|
70
|
+
$[9] = t3;
|
|
71
|
+
} else {
|
|
72
|
+
t3 = $[9];
|
|
73
|
+
}
|
|
74
|
+
return t3;
|
|
75
|
+
}
|
|
76
|
+
/** A ghost tool button for the composer `toolbar`, such as attach (web `PromptInputButton`). Give it `icon` and `label`. */
|
|
77
|
+
export function PromptInputButton(props) {
|
|
78
|
+
const $ = _c(2);
|
|
79
|
+
let t0;
|
|
80
|
+
if ($[0] !== props) {
|
|
81
|
+
t0 = <ChatIconButton variant="ghost" {...props} />;
|
|
82
|
+
$[0] = props;
|
|
83
|
+
$[1] = t0;
|
|
84
|
+
} else {
|
|
85
|
+
t0 = $[1];
|
|
86
|
+
}
|
|
87
|
+
return t0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* The web `ModelPicker` trigger (`model-picker.tsx` `TRIGGER_CLASS`), the
|
|
92
|
+
* chip a composer footer holds: `h-7 gap-1.5 rounded-md px-2`, a 14 icon, the
|
|
93
|
+
* suffix at `/70` after " · ", and a 12 chevron at `opacity-60`. The label is
|
|
94
|
+
* `text-sm` (14), the phone floor for tappable text (the web is `text-xs`).
|
|
95
|
+
*/
|
|
96
|
+
export const PROMPT_INPUT_CHIP = {
|
|
97
|
+
height: 28,
|
|
98
|
+
paddingX: 8,
|
|
99
|
+
gap: 6,
|
|
100
|
+
radius: tokens.radius.md,
|
|
101
|
+
iconSize: 14,
|
|
102
|
+
chevronSize: 12,
|
|
103
|
+
chevronOpacity: 0.6,
|
|
104
|
+
suffixOpacity: 0.7,
|
|
105
|
+
/** The narrowest label worth drawing: about two characters and the ellipsis at `text-sm` (2em). */
|
|
106
|
+
labelMinWidth: 28,
|
|
107
|
+
/** `size="touch"`: 36 on screen, 4 slop above and below, so a 44 bar holds its whole target. */
|
|
108
|
+
touchHeight: 36
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* A chip for the composer `footer`, the web `ModelPicker` trigger: 28 high on
|
|
112
|
+
* screen (36 with `size="touch"`), slop to 44 above and below. The label shrinks and truncates, so a
|
|
113
|
+
* long model name gives up width to the chips beside it, as the web
|
|
114
|
+
* `max-sm:truncate`; the icon and chevron keep their size. Below
|
|
115
|
+
* `labelMinWidth` (scaled by the system font size) the label hides, so a
|
|
116
|
+
* squeezed chip is its icon and chevron, as the web at 390, not a sliver of a
|
|
117
|
+
* letter. Disabled dims to 50%, as the web `disabled:opacity-50`.
|
|
118
|
+
*/
|
|
119
|
+
export function PromptInputChip(t0) {
|
|
120
|
+
const $ = _c(60);
|
|
121
|
+
const {
|
|
122
|
+
icon,
|
|
123
|
+
label,
|
|
124
|
+
suffix,
|
|
125
|
+
count,
|
|
126
|
+
chevron: t1,
|
|
127
|
+
weight: t2,
|
|
128
|
+
color,
|
|
129
|
+
accessibilityLabel,
|
|
130
|
+
expanded,
|
|
131
|
+
disabled: t3,
|
|
132
|
+
size: t4,
|
|
133
|
+
onPress,
|
|
134
|
+
testID
|
|
135
|
+
} = t0;
|
|
136
|
+
const chevron = t1 === undefined ? true : t1;
|
|
137
|
+
const weight = t2 === undefined ? "medium" : t2;
|
|
138
|
+
const disabled = t3 === undefined ? false : t3;
|
|
139
|
+
const size = t4 === undefined ? "sm" : t4;
|
|
140
|
+
const height = size === "touch" ? PROMPT_INPUT_CHIP.touchHeight : PROMPT_INPUT_CHIP.height;
|
|
141
|
+
const scheme = useScheme();
|
|
142
|
+
const pressed = usePressFeedback();
|
|
143
|
+
const {
|
|
144
|
+
fontScale
|
|
145
|
+
} = useWindowDimensions();
|
|
146
|
+
const [readable, setReadable] = useState(true);
|
|
147
|
+
const tint = color ?? tokens.color.muted[scheme];
|
|
148
|
+
let t5;
|
|
149
|
+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
150
|
+
t5 = sizeStyle("text-sm");
|
|
151
|
+
$[0] = t5;
|
|
152
|
+
} else {
|
|
153
|
+
t5 = $[0];
|
|
154
|
+
}
|
|
155
|
+
let t6;
|
|
156
|
+
if ($[1] !== tint) {
|
|
157
|
+
t6 = [t5, {
|
|
158
|
+
color: tint
|
|
159
|
+
}];
|
|
160
|
+
$[1] = tint;
|
|
161
|
+
$[2] = t6;
|
|
162
|
+
} else {
|
|
163
|
+
t6 = $[2];
|
|
164
|
+
}
|
|
165
|
+
const text = t6;
|
|
166
|
+
let t7;
|
|
167
|
+
if ($[3] !== accessibilityLabel || $[4] !== count || $[5] !== label || $[6] !== suffix) {
|
|
168
|
+
t7 = accessibilityLabel ?? [label, suffix, count].filter(_temp).join(", ");
|
|
169
|
+
$[3] = accessibilityLabel;
|
|
170
|
+
$[4] = count;
|
|
171
|
+
$[5] = label;
|
|
172
|
+
$[6] = suffix;
|
|
173
|
+
$[7] = t7;
|
|
174
|
+
} else {
|
|
175
|
+
t7 = $[7];
|
|
176
|
+
}
|
|
177
|
+
const name = t7;
|
|
178
|
+
let t8;
|
|
179
|
+
if ($[8] !== disabled || $[9] !== expanded) {
|
|
180
|
+
t8 = {
|
|
181
|
+
disabled,
|
|
182
|
+
expanded
|
|
183
|
+
};
|
|
184
|
+
$[8] = disabled;
|
|
185
|
+
$[9] = expanded;
|
|
186
|
+
$[10] = t8;
|
|
187
|
+
} else {
|
|
188
|
+
t8 = $[10];
|
|
189
|
+
}
|
|
190
|
+
let t9;
|
|
191
|
+
if ($[11] !== height) {
|
|
192
|
+
t9 = touchSlop(MIN_TOUCH_TARGET, height);
|
|
193
|
+
$[11] = height;
|
|
194
|
+
$[12] = t9;
|
|
195
|
+
} else {
|
|
196
|
+
t9 = $[12];
|
|
197
|
+
}
|
|
198
|
+
const t10 = disabled && "opacity-50";
|
|
199
|
+
let t11;
|
|
200
|
+
if ($[13] !== pressed || $[14] !== t10) {
|
|
201
|
+
t11 = cn("min-w-0 shrink flex-row items-center", pressed, t10);
|
|
202
|
+
$[13] = pressed;
|
|
203
|
+
$[14] = t10;
|
|
204
|
+
$[15] = t11;
|
|
205
|
+
} else {
|
|
206
|
+
t11 = $[15];
|
|
207
|
+
}
|
|
208
|
+
let t12;
|
|
209
|
+
if ($[16] !== height) {
|
|
210
|
+
t12 = {
|
|
211
|
+
minHeight: height,
|
|
212
|
+
paddingHorizontal: PROMPT_INPUT_CHIP.paddingX,
|
|
213
|
+
gap: PROMPT_INPUT_CHIP.gap,
|
|
214
|
+
borderRadius: PROMPT_INPUT_CHIP.radius
|
|
215
|
+
};
|
|
216
|
+
$[16] = height;
|
|
217
|
+
$[17] = t12;
|
|
218
|
+
} else {
|
|
219
|
+
t12 = $[17];
|
|
220
|
+
}
|
|
221
|
+
let t13;
|
|
222
|
+
if ($[18] !== icon) {
|
|
223
|
+
t13 = icon ? <View className="shrink-0">{icon}</View> : null;
|
|
224
|
+
$[18] = icon;
|
|
225
|
+
$[19] = t13;
|
|
226
|
+
} else {
|
|
227
|
+
t13 = $[19];
|
|
228
|
+
}
|
|
229
|
+
let t14;
|
|
230
|
+
if ($[20] !== fontScale) {
|
|
231
|
+
t14 = event => setReadable(event.nativeEvent.layout.width >= PROMPT_INPUT_CHIP.labelMinWidth * Math.max(1, fontScale));
|
|
232
|
+
$[20] = fontScale;
|
|
233
|
+
$[21] = t14;
|
|
234
|
+
} else {
|
|
235
|
+
t14 = $[21];
|
|
236
|
+
}
|
|
237
|
+
const t15 = weight === "medium" ? "font-instrument-sans-medium" : "font-instrument-sans";
|
|
238
|
+
let t16;
|
|
239
|
+
if ($[22] !== t15) {
|
|
240
|
+
t16 = cn("min-w-0 shrink text-sm", t15);
|
|
241
|
+
$[22] = t15;
|
|
242
|
+
$[23] = t16;
|
|
243
|
+
} else {
|
|
244
|
+
t16 = $[23];
|
|
245
|
+
}
|
|
246
|
+
let t17;
|
|
247
|
+
if ($[24] !== weight) {
|
|
248
|
+
t17 = weight === "medium" ? typeStyle("medium") : null;
|
|
249
|
+
$[24] = weight;
|
|
250
|
+
$[25] = t17;
|
|
251
|
+
} else {
|
|
252
|
+
t17 = $[25];
|
|
253
|
+
}
|
|
254
|
+
let t18;
|
|
255
|
+
if ($[26] !== readable) {
|
|
256
|
+
t18 = readable ? null : {
|
|
257
|
+
opacity: 0
|
|
258
|
+
};
|
|
259
|
+
$[26] = readable;
|
|
260
|
+
$[27] = t18;
|
|
261
|
+
} else {
|
|
262
|
+
t18 = $[27];
|
|
263
|
+
}
|
|
264
|
+
let t19;
|
|
265
|
+
if ($[28] !== t17 || $[29] !== t18 || $[30] !== text) {
|
|
266
|
+
t19 = [...text, t17, t18];
|
|
267
|
+
$[28] = t17;
|
|
268
|
+
$[29] = t18;
|
|
269
|
+
$[30] = text;
|
|
270
|
+
$[31] = t19;
|
|
271
|
+
} else {
|
|
272
|
+
t19 = $[31];
|
|
273
|
+
}
|
|
274
|
+
let t20;
|
|
275
|
+
if ($[32] !== suffix || $[33] !== tint) {
|
|
276
|
+
t20 = suffix ? <Text style={{
|
|
277
|
+
color: withAlpha(tint, PROMPT_INPUT_CHIP.suffixOpacity)
|
|
278
|
+
}}>{` · ${suffix}`}</Text> : null;
|
|
279
|
+
$[32] = suffix;
|
|
280
|
+
$[33] = tint;
|
|
281
|
+
$[34] = t20;
|
|
282
|
+
} else {
|
|
283
|
+
t20 = $[34];
|
|
284
|
+
}
|
|
285
|
+
let t21;
|
|
286
|
+
if ($[35] !== label || $[36] !== t14 || $[37] !== t16 || $[38] !== t19 || $[39] !== t20) {
|
|
287
|
+
t21 = <Text numberOfLines={1} onLayout={t14} className={t16} style={t19}>{label}{t20}</Text>;
|
|
288
|
+
$[35] = label;
|
|
289
|
+
$[36] = t14;
|
|
290
|
+
$[37] = t16;
|
|
291
|
+
$[38] = t19;
|
|
292
|
+
$[39] = t20;
|
|
293
|
+
$[40] = t21;
|
|
294
|
+
} else {
|
|
295
|
+
t21 = $[40];
|
|
296
|
+
}
|
|
297
|
+
let t22;
|
|
298
|
+
if ($[41] !== count || $[42] !== text) {
|
|
299
|
+
t22 = count !== undefined ? <Text className="font-instrument-sans-medium text-sm" style={[...text, typeStyle("medium"), {
|
|
300
|
+
fontVariant: ["tabular-nums"]
|
|
301
|
+
}]}>{count}</Text> : null;
|
|
302
|
+
$[41] = count;
|
|
303
|
+
$[42] = text;
|
|
304
|
+
$[43] = t22;
|
|
305
|
+
} else {
|
|
306
|
+
t22 = $[43];
|
|
307
|
+
}
|
|
308
|
+
let t23;
|
|
309
|
+
if ($[44] !== chevron || $[45] !== tint) {
|
|
310
|
+
t23 = chevron ? <View style={{
|
|
311
|
+
opacity: PROMPT_INPUT_CHIP.chevronOpacity
|
|
312
|
+
}}><IconChevronDown size={PROMPT_INPUT_CHIP.chevronSize} color={tint} /></View> : null;
|
|
313
|
+
$[44] = chevron;
|
|
314
|
+
$[45] = tint;
|
|
315
|
+
$[46] = t23;
|
|
316
|
+
} else {
|
|
317
|
+
t23 = $[46];
|
|
318
|
+
}
|
|
319
|
+
let t24;
|
|
320
|
+
if ($[47] !== disabled || $[48] !== name || $[49] !== onPress || $[50] !== t11 || $[51] !== t12 || $[52] !== t13 || $[53] !== t21 || $[54] !== t22 || $[55] !== t23 || $[56] !== t8 || $[57] !== t9 || $[58] !== testID) {
|
|
321
|
+
t24 = <Pressable testID={testID} accessibilityRole="button" accessibilityLabel={name} accessibilityState={t8} disabled={disabled} onPress={onPress} hitSlop={t9} className={t11} style={t12}>{t13}{t21}{t22}{t23}</Pressable>;
|
|
322
|
+
$[47] = disabled;
|
|
323
|
+
$[48] = name;
|
|
324
|
+
$[49] = onPress;
|
|
325
|
+
$[50] = t11;
|
|
326
|
+
$[51] = t12;
|
|
327
|
+
$[52] = t13;
|
|
328
|
+
$[53] = t21;
|
|
329
|
+
$[54] = t22;
|
|
330
|
+
$[55] = t23;
|
|
331
|
+
$[56] = t8;
|
|
332
|
+
$[57] = t9;
|
|
333
|
+
$[58] = testID;
|
|
334
|
+
$[59] = t24;
|
|
335
|
+
} else {
|
|
336
|
+
t24 = $[59];
|
|
337
|
+
}
|
|
338
|
+
return t24;
|
|
339
|
+
}
|
|
340
|
+
function _temp(part) {
|
|
341
|
+
return part !== undefined;
|
|
342
|
+
}
|
|
343
|
+
/** The web `Composer` inline radius, `rounded-[1.25rem]`. */
|
|
344
|
+
const INLINE_RADIUS = 20;
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Eva's `pill` composer: 48 high on one line (border 1, then 5 around a 36
|
|
348
|
+
* field: the web `h-12 py-1` centres the 36 field and send button in 38),
|
|
349
|
+
* `pl-1.5` / `pr-1.5`, and radius 24 (`rounded-full` at 48). Its placeholder
|
|
350
|
+
* is the muted colour at 90% (`data-empty:before:text-muted-foreground/90`).
|
|
351
|
+
*/
|
|
352
|
+
const PILL = {
|
|
353
|
+
radius: 24,
|
|
354
|
+
paddingY: 5,
|
|
355
|
+
paddingX: 6,
|
|
356
|
+
lineHeight: 36,
|
|
357
|
+
placeholderAlpha: 0.9
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
/** The field grows to this height, then scrolls: about 6 lines of 24 (with `py-2.5`), and about 8 of `text-xl` with larger text. */
|
|
361
|
+
const MAX_FIELD_HEIGHT = {
|
|
362
|
+
regular: 160,
|
|
363
|
+
larger: 240
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* React Native Web draws a multiline field as a `textarea` with the HTML
|
|
368
|
+
* default of 2 rows, and the auto-grow keeps that height. One row there; on
|
|
369
|
+
* native, `numberOfLines` would lock the line count on Android, so none.
|
|
370
|
+
*/
|
|
371
|
+
const ONE_ROW = Platform.OS === "web" ? 1 : undefined;
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* The chat composer: the web `PromptInput` field (`rounded-field border
|
|
375
|
+
* bg-field-background`, `fieldStyle`) with an optional `header` row, a
|
|
376
|
+
* multiline field that grows from one line, and a footer of `toolbar` tools
|
|
377
|
+
* and the send / stop button. It sits in a `KeyboardAvoidingView` (padding,
|
|
378
|
+
* on iOS and Android; frame by frame with `KeyboardControllerProvider`) and
|
|
379
|
+
* pads the safe-area insets, so put it last in a full-height column, under the
|
|
380
|
+
* `Conversation`. Inside a part that lifts it already (`ConversationDock`
|
|
381
|
+
* with `KeyboardControllerProvider`, `ChatThread`) it adds no lift of its own.
|
|
382
|
+
*/
|
|
383
|
+
export function PromptInput(t0) {
|
|
384
|
+
const $ = _c(65);
|
|
385
|
+
const {
|
|
386
|
+
value,
|
|
387
|
+
defaultValue: t1,
|
|
388
|
+
onChangeText,
|
|
389
|
+
onSubmit,
|
|
390
|
+
status,
|
|
391
|
+
onStop,
|
|
392
|
+
placeholder: t2,
|
|
393
|
+
accessibilityLabel: t3,
|
|
394
|
+
replyTo,
|
|
395
|
+
header,
|
|
396
|
+
toolbar,
|
|
397
|
+
footer,
|
|
398
|
+
menu,
|
|
399
|
+
layout: t4,
|
|
400
|
+
shape: t5,
|
|
401
|
+
leading,
|
|
402
|
+
disabled: t6,
|
|
403
|
+
safeBottom: t7,
|
|
404
|
+
keyboardVerticalOffset: t8,
|
|
405
|
+
className,
|
|
406
|
+
testID
|
|
407
|
+
} = t0;
|
|
408
|
+
const defaultValue = t1 === undefined ? "" : t1;
|
|
409
|
+
const placeholder = t2 === undefined ? "What would you like to know?" : t2;
|
|
410
|
+
const accessibilityLabel = t3 === undefined ? "Message" : t3;
|
|
411
|
+
const layout = t4 === undefined ? "stacked" : t4;
|
|
412
|
+
const shape = t5 === undefined ? "rounded" : t5;
|
|
413
|
+
const disabled = t6 === undefined ? false : t6;
|
|
414
|
+
const safeBottom = t7 === undefined ? true : t7;
|
|
415
|
+
const keyboardVerticalOffset = t8 === undefined ? 0 : t8;
|
|
416
|
+
const scheme = useScheme();
|
|
417
|
+
const largerText = useLargerText();
|
|
418
|
+
const insets = useSafeAreaInsets();
|
|
419
|
+
const lifted = useContext(KeyboardLiftContext);
|
|
420
|
+
let t9;
|
|
421
|
+
if ($[0] !== defaultValue || $[1] !== onChangeText || $[2] !== value) {
|
|
422
|
+
t9 = {
|
|
423
|
+
value,
|
|
424
|
+
defaultValue,
|
|
425
|
+
onChange: onChangeText
|
|
426
|
+
};
|
|
427
|
+
$[0] = defaultValue;
|
|
428
|
+
$[1] = onChangeText;
|
|
429
|
+
$[2] = value;
|
|
430
|
+
$[3] = t9;
|
|
431
|
+
} else {
|
|
432
|
+
t9 = $[3];
|
|
433
|
+
}
|
|
434
|
+
const [text, setText] = useControllableState(t9);
|
|
435
|
+
let t10;
|
|
436
|
+
if ($[4] !== text) {
|
|
437
|
+
t10 = text.trim();
|
|
438
|
+
$[4] = text;
|
|
439
|
+
$[5] = t10;
|
|
440
|
+
} else {
|
|
441
|
+
t10 = $[5];
|
|
442
|
+
}
|
|
443
|
+
const message = t10;
|
|
444
|
+
let t11;
|
|
445
|
+
if ($[6] !== disabled || $[7] !== message.length || $[8] !== status) {
|
|
446
|
+
t11 = message.length > 0 && !disabled && !isGenerating(status);
|
|
447
|
+
$[6] = disabled;
|
|
448
|
+
$[7] = message.length;
|
|
449
|
+
$[8] = status;
|
|
450
|
+
$[9] = t11;
|
|
451
|
+
} else {
|
|
452
|
+
t11 = $[9];
|
|
453
|
+
}
|
|
454
|
+
const canSubmit = t11;
|
|
455
|
+
const bottom = safeBottom ? insets.bottom : 0;
|
|
456
|
+
const [contentHeight, setContentHeight] = useState(0);
|
|
457
|
+
const maxHeight = largerText ? MAX_FIELD_HEIGHT.larger : MAX_FIELD_HEIGHT.regular;
|
|
458
|
+
let t12;
|
|
459
|
+
if ($[10] !== contentHeight || $[11] !== maxHeight) {
|
|
460
|
+
t12 = contentHeight > 0 ? {
|
|
461
|
+
height: Math.min(contentHeight, maxHeight)
|
|
462
|
+
} : null;
|
|
463
|
+
$[10] = contentHeight;
|
|
464
|
+
$[11] = maxHeight;
|
|
465
|
+
$[12] = t12;
|
|
466
|
+
} else {
|
|
467
|
+
t12 = $[12];
|
|
468
|
+
}
|
|
469
|
+
const growStyle = t12;
|
|
470
|
+
const scrollEnabled = contentHeight > maxHeight;
|
|
471
|
+
const pill = layout === "inline" && shape === "pill";
|
|
472
|
+
let t13;
|
|
473
|
+
if ($[13] !== largerText || $[14] !== layout || $[15] !== pill) {
|
|
474
|
+
t13 = largerText ? sizeStyle("text-xl") : layout === "inline" ? {
|
|
475
|
+
fontSize: 14,
|
|
476
|
+
lineHeight: pill ? 20 : 24
|
|
477
|
+
} : sizeStyle("text-base");
|
|
478
|
+
$[13] = largerText;
|
|
479
|
+
$[14] = layout;
|
|
480
|
+
$[15] = pill;
|
|
481
|
+
$[16] = t13;
|
|
482
|
+
} else {
|
|
483
|
+
t13 = $[16];
|
|
484
|
+
}
|
|
485
|
+
const fieldText = t13;
|
|
486
|
+
let t14;
|
|
487
|
+
if ($[17] !== setText) {
|
|
488
|
+
t14 = next => {
|
|
489
|
+
setText(next);
|
|
490
|
+
if (next === "") {
|
|
491
|
+
setContentHeight(0);
|
|
492
|
+
}
|
|
493
|
+
};
|
|
494
|
+
$[17] = setText;
|
|
495
|
+
$[18] = t14;
|
|
496
|
+
} else {
|
|
497
|
+
t14 = $[18];
|
|
498
|
+
}
|
|
499
|
+
const changeText = t14;
|
|
500
|
+
let t15;
|
|
501
|
+
if ($[19] !== canSubmit || $[20] !== message || $[21] !== onSubmit || $[22] !== setText) {
|
|
502
|
+
t15 = () => {
|
|
503
|
+
if (!canSubmit) {
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
onSubmit(message);
|
|
507
|
+
setText("");
|
|
508
|
+
setContentHeight(0);
|
|
509
|
+
};
|
|
510
|
+
$[19] = canSubmit;
|
|
511
|
+
$[20] = message;
|
|
512
|
+
$[21] = onSubmit;
|
|
513
|
+
$[22] = setText;
|
|
514
|
+
$[23] = t15;
|
|
515
|
+
} else {
|
|
516
|
+
t15 = $[23];
|
|
517
|
+
}
|
|
518
|
+
const submit = t15;
|
|
519
|
+
let t16;
|
|
520
|
+
if ($[24] !== className) {
|
|
521
|
+
t16 = cn("pt-2", className);
|
|
522
|
+
$[24] = className;
|
|
523
|
+
$[25] = t16;
|
|
524
|
+
} else {
|
|
525
|
+
t16 = $[25];
|
|
526
|
+
}
|
|
527
|
+
const t17 = bottom + 8;
|
|
528
|
+
const t18 = insets.left + 12;
|
|
529
|
+
const t19 = insets.right + 12;
|
|
530
|
+
let t20;
|
|
531
|
+
if ($[26] !== t17 || $[27] !== t18 || $[28] !== t19) {
|
|
532
|
+
t20 = {
|
|
533
|
+
paddingBottom: t17,
|
|
534
|
+
paddingLeft: t18,
|
|
535
|
+
paddingRight: t19
|
|
536
|
+
};
|
|
537
|
+
$[26] = t17;
|
|
538
|
+
$[27] = t18;
|
|
539
|
+
$[28] = t19;
|
|
540
|
+
$[29] = t20;
|
|
541
|
+
} else {
|
|
542
|
+
t20 = $[29];
|
|
543
|
+
}
|
|
544
|
+
let t21;
|
|
545
|
+
if ($[30] !== menu) {
|
|
546
|
+
t21 = menu ? <View className="mb-1.5">{menu}</View> : null;
|
|
547
|
+
$[30] = menu;
|
|
548
|
+
$[31] = t21;
|
|
549
|
+
} else {
|
|
550
|
+
t21 = $[31];
|
|
551
|
+
}
|
|
552
|
+
let t22;
|
|
553
|
+
if ($[32] !== accessibilityLabel || $[33] !== canSubmit || $[34] !== changeText || $[35] !== disabled || $[36] !== fieldText || $[37] !== growStyle || $[38] !== header || $[39] !== largerText || $[40] !== layout || $[41] !== leading || $[42] !== maxHeight || $[43] !== onStop || $[44] !== pill || $[45] !== placeholder || $[46] !== replyTo || $[47] !== scheme || $[48] !== scrollEnabled || $[49] !== status || $[50] !== submit || $[51] !== testID || $[52] !== text || $[53] !== toolbar) {
|
|
554
|
+
t22 = layout === "inline" ? <View className="border" style={[fieldStyle(scheme), {
|
|
555
|
+
borderRadius: pill ? PILL.radius : INLINE_RADIUS
|
|
556
|
+
}]}>{replyTo ? <View className="px-1.5 pt-1.5">{replyTo}</View> : null}{header ? <View className="flex-row flex-wrap gap-1 px-1.5 pt-1.5">{header}</View> : null}<View className={cn("flex-row items-end gap-1", !pill && "p-1.5")} style={pill ? {
|
|
557
|
+
paddingVertical: PILL.paddingY,
|
|
558
|
+
paddingHorizontal: PILL.paddingX
|
|
559
|
+
} : null}>{leading ? <View className="shrink-0 flex-row items-center gap-1" style={pill ? {
|
|
560
|
+
minHeight: PILL.lineHeight
|
|
561
|
+
} : null}>{leading}</View> : null}<FieldInput testID={testID ? `${testID}-input` : undefined} nativeID={COMPOSER_INPUT_ID} multiline={true} numberOfLines={ONE_ROW} value={text} onChangeText={changeText} placeholder={placeholder} placeholderTextColor={pill ? withAlpha(tokens.color.muted[scheme], PILL.placeholderAlpha) : undefined} accessibilityLabel={accessibilityLabel} editable={!disabled} textAlignVertical="center" scrollEnabled={scrollEnabled} onContentSizeChange={e => setContentHeight(e.nativeEvent.contentSize.height)} className={cn("flex-1 border-0 text-sm font-instrument-sans", pill ? "min-h-9 px-1 py-2" : "min-h-8 px-2 py-1", largerText && "min-h-11 py-2 text-xl font-instrument-sans-medium")} style={[fieldTextStyle(scheme), fieldText, largerText ? typeStyle("medium") : null, {
|
|
562
|
+
backgroundColor: "transparent",
|
|
563
|
+
maxHeight,
|
|
564
|
+
...growStyle
|
|
565
|
+
}]} /><View className="shrink-0 flex-row items-center gap-1" style={pill ? {
|
|
566
|
+
minHeight: PILL.lineHeight
|
|
567
|
+
} : null}>{toolbar}<PromptInputSubmit status={status} onSubmit={submit} onStop={onStop} canSubmit={canSubmit} size={pill ? "md" : undefined} /></View></View></View> : <View className="border" style={fieldStyle(scheme)}>{replyTo ? <View className="px-2 pt-2">{replyTo}</View> : null}{header ? <View className="flex-row flex-wrap gap-1 px-2 pt-2">{header}</View> : null}<FieldInput testID={testID ? `${testID}-input` : undefined} nativeID={COMPOSER_INPUT_ID} multiline={true} numberOfLines={ONE_ROW} value={text} onChangeText={changeText} placeholder={placeholder} accessibilityLabel={accessibilityLabel} editable={!disabled} textAlignVertical="top" scrollEnabled={scrollEnabled} onContentSizeChange={e_0 => setContentHeight(e_0.nativeEvent.contentSize.height)} className={cn("min-h-11 border-0 px-3.5 py-2.5 text-base font-instrument-sans", largerText && "min-h-14 px-4 py-3 text-xl font-instrument-sans-medium")} style={[fieldTextStyle(scheme), fieldText, largerText ? typeStyle("medium") : null, {
|
|
568
|
+
backgroundColor: "transparent",
|
|
569
|
+
maxHeight,
|
|
570
|
+
...growStyle
|
|
571
|
+
}]} /><View className="flex-row items-center justify-between gap-1 px-2 pb-2"><View className="min-w-0 shrink flex-row items-center gap-1">{toolbar}</View><PromptInputSubmit status={status} onSubmit={submit} onStop={onStop} canSubmit={canSubmit} /></View></View>;
|
|
572
|
+
$[32] = accessibilityLabel;
|
|
573
|
+
$[33] = canSubmit;
|
|
574
|
+
$[34] = changeText;
|
|
575
|
+
$[35] = disabled;
|
|
576
|
+
$[36] = fieldText;
|
|
577
|
+
$[37] = growStyle;
|
|
578
|
+
$[38] = header;
|
|
579
|
+
$[39] = largerText;
|
|
580
|
+
$[40] = layout;
|
|
581
|
+
$[41] = leading;
|
|
582
|
+
$[42] = maxHeight;
|
|
583
|
+
$[43] = onStop;
|
|
584
|
+
$[44] = pill;
|
|
585
|
+
$[45] = placeholder;
|
|
586
|
+
$[46] = replyTo;
|
|
587
|
+
$[47] = scheme;
|
|
588
|
+
$[48] = scrollEnabled;
|
|
589
|
+
$[49] = status;
|
|
590
|
+
$[50] = submit;
|
|
591
|
+
$[51] = testID;
|
|
592
|
+
$[52] = text;
|
|
593
|
+
$[53] = toolbar;
|
|
594
|
+
$[54] = t22;
|
|
595
|
+
} else {
|
|
596
|
+
t22 = $[54];
|
|
597
|
+
}
|
|
598
|
+
let t23;
|
|
599
|
+
if ($[55] !== footer || $[56] !== t16 || $[57] !== t20 || $[58] !== t21 || $[59] !== t22 || $[60] !== testID) {
|
|
600
|
+
t23 = <View testID={testID} className={t16} style={t20}>{t21}{t22}{footer}</View>;
|
|
601
|
+
$[55] = footer;
|
|
602
|
+
$[56] = t16;
|
|
603
|
+
$[57] = t20;
|
|
604
|
+
$[58] = t21;
|
|
605
|
+
$[59] = t22;
|
|
606
|
+
$[60] = testID;
|
|
607
|
+
$[61] = t23;
|
|
608
|
+
} else {
|
|
609
|
+
t23 = $[61];
|
|
610
|
+
}
|
|
611
|
+
const composer = t23;
|
|
612
|
+
if (lifted) {
|
|
613
|
+
return composer;
|
|
614
|
+
}
|
|
615
|
+
const t24 = keyboardVerticalOffset - bottom;
|
|
616
|
+
let t25;
|
|
617
|
+
if ($[62] !== composer || $[63] !== t24) {
|
|
618
|
+
t25 = <KeyboardAvoidingView keyboardVerticalOffset={t24}>{composer}</KeyboardAvoidingView>;
|
|
619
|
+
$[62] = composer;
|
|
620
|
+
$[63] = t24;
|
|
621
|
+
$[64] = t25;
|
|
622
|
+
} else {
|
|
623
|
+
t25 = $[64];
|
|
624
|
+
}
|
|
625
|
+
return t25;
|
|
626
|
+
}
|