@xsolla/xui-textarea 0.213.1 → 0.214.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Textarea
2
2
 
3
- A cross-platform React textarea component for multi-line text input. Includes error state and validation message support.
3
+ A cross-platform React textarea component for multi-line text input. Includes error and warning states and validation message support.
4
4
  <!-- BEGIN:xui-mcp-instructions:textarea -->
5
5
  A multi-line text input for collecting longer freeform content. Supports five sizes, an optional scroll bar, an optional resize handle, placeholder text, and the full standard input state set. Used wherever the expected input length exceeds a single line — comments, descriptions, messages, notes, and code snippets.
6
6
 
@@ -70,6 +70,21 @@ The resize handle must be keyboard-operable if implemented. Consider providing
70
70
  npm install @xsolla/xui-textarea
71
71
  ```
72
72
 
73
+ ## Validation states
74
+
75
+ | State | Prop | Meaning |
76
+ | :-------- | :------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------- |
77
+ | Error | `errorMessage` (or `state="error"`) | Blocking. The value is invalid and must be fixed before the form can be submitted. |
78
+ | Warning | `warningMessage` (or `state="warning"`) | Non-blocking. The value is allowed but needs attention — e.g. an empty optional field the user probably meant to fill in. |
79
+
80
+ Passing `errorMessage` or `warningMessage` implies the matching state, so `state`
81
+ is only needed when you want the border highlight **without** a message below the
82
+ field — for forms that render validation text somewhere else (a form-level error
83
+ summary, a shared label, a tooltip).
84
+
85
+ Error takes precedence over warning: when both are supplied, the field renders as
86
+ an error and the warning is suppressed.
87
+
73
88
  ## Demo
74
89
 
75
90
  ### Basic Textarea
@@ -135,6 +150,47 @@ export default function TextareaWithError() {
135
150
  }
136
151
  ```
137
152
 
153
+ ### Textarea with Warning
154
+
155
+ ```tsx
156
+ import * as React from "react";
157
+ import { TextArea } from "@xsolla/xui-textarea";
158
+
159
+ export default function TextareaWithWarning() {
160
+ const [value, setValue] = React.useState("");
161
+
162
+ return (
163
+ <TextArea
164
+ value={value}
165
+ onChangeText={setValue}
166
+ placeholder="Description (optional)"
167
+ warningMessage={
168
+ value.trim() === ""
169
+ ? "Adding a description helps reviewers understand your request"
170
+ : undefined
171
+ }
172
+ />
173
+ );
174
+ }
175
+ ```
176
+
177
+ ### Border Highlight Without a Message
178
+
179
+ ```tsx
180
+ import * as React from "react";
181
+ import { TextArea } from "@xsolla/xui-textarea";
182
+
183
+ export default function TextareaBorderHighlight() {
184
+ return (
185
+ <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
186
+ {/* The validation text lives in a form-level summary elsewhere */}
187
+ <TextArea state="warning" placeholder="Needs attention" />
188
+ <TextArea state="error" placeholder="Invalid" />
189
+ </div>
190
+ );
191
+ }
192
+ ```
193
+
138
194
  ### Textarea with Blur Validation
139
195
 
140
196
  ```tsx
@@ -173,7 +229,9 @@ import { TextArea } from "@xsolla/xui-textarea";
173
229
  placeholder="Placeholder" // Placeholder text
174
230
  size="md" // Size variant
175
231
  disabled={false} // Disabled state
232
+ state="default" // Border highlight without a message
176
233
  errorMessage="Error text" // Error message below textarea
234
+ warningMessage="Warning text" // Warning message below textarea
177
235
  />;
178
236
  ```
179
237
 
@@ -227,6 +285,37 @@ export default function DisabledTextarea() {
227
285
  }
228
286
  ```
229
287
 
288
+ ### Soft Validation on Blur
289
+
290
+ ```tsx
291
+ import * as React from "react";
292
+ import { TextArea } from "@xsolla/xui-textarea";
293
+
294
+ export default function TextareaSoftValidation() {
295
+ const [value, setValue] = React.useState("");
296
+ const [warning, setWarning] = React.useState<string | undefined>(undefined);
297
+
298
+ // An empty value is permitted, so the form can still be submitted — the
299
+ // field simply nudges the user instead of reporting an error.
300
+ return (
301
+ <TextArea
302
+ value={value}
303
+ onChangeText={setValue}
304
+ onBlur={() =>
305
+ setWarning(
306
+ value.trim() === ""
307
+ ? "Adding a description helps reviewers understand your request"
308
+ : undefined
309
+ )
310
+ }
311
+ onFocus={() => setWarning(undefined)}
312
+ warningMessage={warning}
313
+ placeholder="Description (optional)"
314
+ />
315
+ );
316
+ }
317
+ ```
318
+
230
319
  ### Character Counter
231
320
 
232
321
  ```tsx
@@ -269,21 +358,23 @@ A multi-line text input component.
269
358
 
270
359
  **TextArea Props:**
271
360
 
272
- | Prop | Type | Default | Description |
273
- | :--------------- | :------------------------------------- | :------ | :------------------------------------------------------------------------------------------------------------ |
274
- | `testID` | `string` | — | Test ID for testing frameworks. On web this renders as `data-testid`; on React Native it renders as `testID`. |
275
- | value | `string` | - | The controlled value of the textarea. |
276
- | placeholder | `string` | - | Placeholder text when empty. |
277
- | onChangeText | `(text: string) => void` | - | Callback when text changes. |
278
- | onBlur | `() => void` | - | Callback fired when the textarea loses focus. Ideal for blur-based validation. |
279
- | onFocus | `() => void` | - | Callback fired when the textarea gains focus. |
280
- | size | `"xl" \| "lg" \| "md" \| "sm" \| "xs"` | `"md"` | Size of the textarea. |
281
- | disabled | `boolean` | `false` | Whether the textarea is disabled. |
282
- | errorMessage | `string` | - | Error message displayed below. |
283
- | aria-label | `string` | - | Accessible label. |
284
- | aria-describedby | `string` | - | ID of description element. |
285
- | id | `string` | - | HTML id attribute. |
286
- | testID | `string` | - | Test identifier. |
361
+ | Prop | Type | Default | Description |
362
+ | :--------------- | :--------------------------------------- | :------------ | :-------------------------------------------------------------------------------------------------------------- |
363
+ | `testID` | `string` | — | Test ID for testing frameworks. On web this renders as `data-testid`; on React Native it renders as `testID`. |
364
+ | value | `string` | - | The controlled value of the textarea. |
365
+ | placeholder | `string` | - | Placeholder text when empty. |
366
+ | onChangeText | `(text: string) => void` | - | Callback when text changes. |
367
+ | onBlur | `() => void` | - | Callback fired when the textarea loses focus. Ideal for blur-based validation. |
368
+ | onFocus | `() => void` | - | Callback fired when the textarea gains focus. |
369
+ | size | `"xl" \| "lg" \| "md" \| "sm" \| "xs"` | `"md"` | Size of the textarea. |
370
+ | disabled | `boolean` | `false` | Whether the textarea is disabled. |
371
+ | state | `"default" \| "warning" \| "error"` | `"default"` | Validation state driving the border highlight, independent of any message. Error takes precedence over warning. |
372
+ | errorMessage | `string` | - | Error message displayed below. Implies `state="error"`. |
373
+ | warningMessage | `string` | - | Warning message displayed below. Implies `state="warning"`. Ignored in the error state. |
374
+ | aria-label | `string` | - | Accessible label. |
375
+ | aria-describedby | `string` | - | ID of description element. |
376
+ | id | `string` | - | HTML id attribute. |
377
+ | testID | `string` | - | Test identifier. |
287
378
 
288
379
  **Padding by Size:**
289
380
 
@@ -295,11 +386,20 @@ A multi-line text input component.
295
386
  | sm | 10px |
296
387
  | xs | 10px |
297
388
 
389
+ **Validation state tokens:**
390
+
391
+ | State | Border | Message text |
392
+ | :------ | :---------------------------- | :--------------------------------------- |
393
+ | error | `theme.colors.border.alert` | `theme.colors.content.alert.primary` |
394
+ | warning | `theme.colors.border.warning` | `theme.colors.content.warning.primary` |
395
+
298
396
  ## Accessibility
299
397
 
300
398
  - Uses native `<textarea>` element
301
- - `aria-invalid` set when error message present
399
+ - `aria-invalid` set for the error state only — a warning is not an invalid value, so it is never marked invalid
302
400
  - `aria-disabled` for disabled state
303
- - `aria-describedby` links to error message
304
- - Error message has `role="alert"` for announcements
401
+ - `aria-describedby` links to the error or warning message when one is rendered
402
+ - Error message has `role="alert"` for immediate announcements
403
+ - Warning message has `role="status"` so it is announced politely, without interrupting the user
305
404
  - Focus indicator follows WCAG guidelines
405
+ - Because a border highlight alone is a colour-only signal, when using `state` without a message make sure the corresponding validation text is rendered elsewhere and associated with the field via `aria-describedby`
@@ -24,8 +24,30 @@ interface TextAreaProps extends ThemeOverrideProps {
24
24
  textColor?: string;
25
25
  /** Whether the textarea is disabled */
26
26
  disabled?: boolean;
27
- /** Error message displayed below the textarea */
27
+ /**
28
+ * Validation state driving the border highlight, independent of any message.
29
+ *
30
+ * Use this when the message is rendered elsewhere (a form-level summary, a
31
+ * sibling label) but the field itself still needs to be highlighted. Passing
32
+ * `errorMessage` or `warningMessage` implies the matching state, so you only
33
+ * need `state` for the message-less case.
34
+ *
35
+ * `"error"` takes precedence over `"warning"`.
36
+ *
37
+ * Defaults to `"default"`.
38
+ */
39
+ state?: "default" | "warning" | "error";
40
+ /** Error message displayed below the textarea. Implies `state="error"` */
28
41
  errorMessage?: string;
42
+ /**
43
+ * Warning message displayed below the textarea. Implies `state="warning"`.
44
+ *
45
+ * A warning is for input that is permitted but undesirable (e.g. an empty
46
+ * optional field the user probably meant to fill in). Unlike an error it does
47
+ * not mark the field invalid, so it is announced politely rather than
48
+ * assertively. Ignored when the textarea is in the error state.
49
+ */
50
+ warningMessage?: string;
29
51
  /** Accessible label for screen readers */
30
52
  "aria-label"?: string;
31
53
  /** ID of element that describes this textarea */
@@ -38,7 +60,18 @@ interface TextAreaProps extends ThemeOverrideProps {
38
60
  * TextArea - An accessible multi-line text input component
39
61
  *
40
62
  * Renders as a semantic `<textarea>` element with full ARIA support.
41
- * Supports labels, error states, and various sizes.
63
+ * Supports labels, error and warning states, and various sizes.
64
+ *
65
+ * ## Validation states
66
+ *
67
+ * - **Error** — blocking. Set `errorMessage`, or `state="error"` to highlight
68
+ * the border only. Marks the field `aria-invalid` and announces the message
69
+ * assertively via `role="alert"`.
70
+ * - **Warning** — non-blocking, "needs attention". Set `warningMessage`, or
71
+ * `state="warning"` to highlight the border only. Does *not* mark the field
72
+ * invalid; the message is announced politely via `role="status"`.
73
+ *
74
+ * Error wins when both are supplied.
42
75
  *
43
76
  * ## Accessibility Features
44
77
  *
@@ -46,6 +79,8 @@ interface TextAreaProps extends ThemeOverrideProps {
46
79
  * - **Keyboard Navigation**: Focusable via Tab
47
80
  * - **ARIA States**: Properly announces disabled and error states
48
81
  * - **Error Announcements**: Error messages use `role="alert"` for immediate announcement
82
+ * - **Warning Announcements**: Warning messages use `role="status"` so they are
83
+ * announced politely without interrupting the user
49
84
  * - **Focus Indicator**: Visible focus ring for keyboard navigation
50
85
  *
51
86
  */
package/native/index.d.ts CHANGED
@@ -24,8 +24,30 @@ interface TextAreaProps extends ThemeOverrideProps {
24
24
  textColor?: string;
25
25
  /** Whether the textarea is disabled */
26
26
  disabled?: boolean;
27
- /** Error message displayed below the textarea */
27
+ /**
28
+ * Validation state driving the border highlight, independent of any message.
29
+ *
30
+ * Use this when the message is rendered elsewhere (a form-level summary, a
31
+ * sibling label) but the field itself still needs to be highlighted. Passing
32
+ * `errorMessage` or `warningMessage` implies the matching state, so you only
33
+ * need `state` for the message-less case.
34
+ *
35
+ * `"error"` takes precedence over `"warning"`.
36
+ *
37
+ * Defaults to `"default"`.
38
+ */
39
+ state?: "default" | "warning" | "error";
40
+ /** Error message displayed below the textarea. Implies `state="error"` */
28
41
  errorMessage?: string;
42
+ /**
43
+ * Warning message displayed below the textarea. Implies `state="warning"`.
44
+ *
45
+ * A warning is for input that is permitted but undesirable (e.g. an empty
46
+ * optional field the user probably meant to fill in). Unlike an error it does
47
+ * not mark the field invalid, so it is announced politely rather than
48
+ * assertively. Ignored when the textarea is in the error state.
49
+ */
50
+ warningMessage?: string;
29
51
  /** Accessible label for screen readers */
30
52
  "aria-label"?: string;
31
53
  /** ID of element that describes this textarea */
@@ -38,7 +60,18 @@ interface TextAreaProps extends ThemeOverrideProps {
38
60
  * TextArea - An accessible multi-line text input component
39
61
  *
40
62
  * Renders as a semantic `<textarea>` element with full ARIA support.
41
- * Supports labels, error states, and various sizes.
63
+ * Supports labels, error and warning states, and various sizes.
64
+ *
65
+ * ## Validation states
66
+ *
67
+ * - **Error** — blocking. Set `errorMessage`, or `state="error"` to highlight
68
+ * the border only. Marks the field `aria-invalid` and announces the message
69
+ * assertively via `role="alert"`.
70
+ * - **Warning** — non-blocking, "needs attention". Set `warningMessage`, or
71
+ * `state="warning"` to highlight the border only. Does *not* mark the field
72
+ * invalid; the message is announced politely via `role="status"`.
73
+ *
74
+ * Error wins when both are supplied.
42
75
  *
43
76
  * ## Accessibility Features
44
77
  *
@@ -46,6 +79,8 @@ interface TextAreaProps extends ThemeOverrideProps {
46
79
  * - **Keyboard Navigation**: Focusable via Tab
47
80
  * - **ARIA States**: Properly announces disabled and error states
48
81
  * - **Error Announcements**: Error messages use `role="alert"` for immediate announcement
82
+ * - **Warning Announcements**: Warning messages use `role="status"` so they are
83
+ * announced politely without interrupting the user
49
84
  * - **Focus Indicator**: Visible focus ring for keyboard navigation
50
85
  *
51
86
  */
package/native/index.js CHANGED
@@ -455,7 +455,9 @@ var TextArea = (0, import_react2.forwardRef)(
455
455
  resize = "vertical",
456
456
  textColor: textColorOverride,
457
457
  disabled = false,
458
+ state = "default",
458
459
  errorMessage,
460
+ warningMessage,
459
461
  "aria-label": ariaLabel,
460
462
  "aria-describedby": ariaDescribedBy,
461
463
  id: externalId,
@@ -468,7 +470,11 @@ var TextArea = (0, import_react2.forwardRef)(
468
470
  const generatedId = (0, import_xui_core.useId)();
469
471
  const textareaId = externalId || generatedId;
470
472
  const errorId = `${textareaId}-error`;
471
- const isError = !!errorMessage;
473
+ const warningId = `${textareaId}-warning`;
474
+ const isError = state === "error" || !!errorMessage;
475
+ const isWarning = !isError && (state === "warning" || !!warningMessage);
476
+ const showErrorMessage = isError && !!errorMessage;
477
+ const showWarningMessage = isWarning && !!warningMessage;
472
478
  const sizeStyles = theme.sizing.textarea(size);
473
479
  const inputColors = theme.colors.control.input;
474
480
  const handleFocus = () => {
@@ -490,6 +496,8 @@ var TextArea = (0, import_react2.forwardRef)(
490
496
  borderColor = inputColors.borderDisable;
491
497
  } else if (isError) {
492
498
  borderColor = theme.colors.border.alert;
499
+ } else if (isWarning) {
500
+ borderColor = theme.colors.border.warning;
493
501
  } else if (isFocused) {
494
502
  backgroundColor = theme.colors.control.focus.bg;
495
503
  borderColor = inputColors.borderHover;
@@ -497,9 +505,12 @@ var TextArea = (0, import_react2.forwardRef)(
497
505
  const textColor = disabled ? inputColors.textDisable : textColorOverride ?? inputColors.text;
498
506
  const placeholderColor = inputColors.placeholder;
499
507
  const describedByIds = [];
500
- if (isError) {
508
+ if (showErrorMessage) {
501
509
  describedByIds.push(errorId);
502
510
  }
511
+ if (showWarningMessage) {
512
+ describedByIds.push(warningId);
513
+ }
503
514
  if (ariaDescribedBy) {
504
515
  describedByIds.push(ariaDescribedBy);
505
516
  }
@@ -528,7 +539,7 @@ var TextArea = (0, import_react2.forwardRef)(
528
539
  position: "relative",
529
540
  cursor: disabled ? "not-allowed" : "text",
530
541
  style: containerStyle,
531
- hoverStyle: !disabled && !isFocused && !isError ? {
542
+ hoverStyle: !disabled && !isFocused && !isError && !isWarning ? {
532
543
  backgroundColor: inputColors.bgHover
533
544
  } : void 0,
534
545
  children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Box, { flex: 1, height: "auto", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -555,7 +566,7 @@ var TextArea = (0, import_react2.forwardRef)(
555
566
  ) })
556
567
  }
557
568
  ),
558
- isError && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
569
+ showErrorMessage && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
559
570
  Text,
560
571
  {
561
572
  id: errorId,
@@ -564,6 +575,16 @@ var TextArea = (0, import_react2.forwardRef)(
564
575
  fontSize: sizeStyles.fontSize - 2,
565
576
  children: errorMessage
566
577
  }
578
+ ),
579
+ showWarningMessage && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
580
+ Text,
581
+ {
582
+ id: warningId,
583
+ role: "status",
584
+ color: theme.colors.content.warning.primary,
585
+ fontSize: sizeStyles.fontSize - 2,
586
+ children: warningMessage
587
+ }
567
588
  )
568
589
  ] });
569
590
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.tsx","../../src/TextArea.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../../../foundation/primitives-native/src/Text.tsx","../../../../foundation/primitives-native/src/TextArea.tsx"],"sourcesContent":["export * from \"./TextArea\";\n","import { useState, forwardRef, type CSSProperties } from \"react\";\nimport { Box, Text, TextAreaPrimitive } from \"@xsolla/xui-primitives\";\nimport {\n useResolvedTheme,\n useId,\n type ThemeOverrideProps,\n} from \"@xsolla/xui-core\";\n\nconst paddingMap: Record<string, number> = {\n xl: 16,\n lg: 14,\n md: 12,\n sm: 10,\n xs: 10,\n};\n\nexport interface TextAreaProps extends ThemeOverrideProps {\n /** Current value of the textarea */\n value?: string;\n /** Placeholder text when empty */\n placeholder?: string;\n /** Event handler when the text changes */\n onChangeText?: (text: string) => void;\n /** Callback fired when the textarea loses focus */\n onBlur?: () => void;\n /** Callback fired when the textarea gains focus */\n onFocus?: () => void;\n /** Size of the textarea */\n size?: \"xl\" | \"lg\" | \"md\" | \"sm\" | \"xs\";\n /** Minimum height of the textarea container, in pixels */\n minHeight?: number;\n /** Maximum height of the textarea container, in pixels */\n maxHeight?: number;\n /** Native resize grip behavior. Defaults to \"vertical\" */\n resize?: \"none\" | \"vertical\" | \"horizontal\" | \"both\";\n /** Override the resolved text color */\n textColor?: string;\n /** Whether the textarea is disabled */\n disabled?: boolean;\n /** Error message displayed below the textarea */\n errorMessage?: string;\n /** Accessible label for screen readers */\n \"aria-label\"?: string;\n /** ID of element that describes this textarea */\n \"aria-describedby\"?: string;\n /** Unique identifier for the textarea element */\n id?: string;\n testID?: string;\n}\n\n/**\n * TextArea - An accessible multi-line text input component\n *\n * Renders as a semantic `<textarea>` element with full ARIA support.\n * Supports labels, error states, and various sizes.\n *\n * ## Accessibility Features\n *\n * - **Semantic HTML**: Renders as a native `<textarea>` element\n * - **Keyboard Navigation**: Focusable via Tab\n * - **ARIA States**: Properly announces disabled and error states\n * - **Error Announcements**: Error messages use `role=\"alert\"` for immediate announcement\n * - **Focus Indicator**: Visible focus ring for keyboard navigation\n *\n */\nexport const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(\n (\n {\n value,\n placeholder,\n onChangeText,\n onBlur: onBlurProp,\n onFocus: onFocusProp,\n size = \"md\",\n minHeight,\n maxHeight,\n resize = \"vertical\",\n textColor: textColorOverride,\n disabled = false,\n errorMessage,\n \"aria-label\": ariaLabel,\n \"aria-describedby\": ariaDescribedBy,\n id: externalId,\n testID,\n themeMode,\n themeProductContext,\n },\n ref\n ) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const [isFocused, setIsFocused] = useState(false);\n\n const generatedId = useId();\n const textareaId = externalId || generatedId;\n const errorId = `${textareaId}-error`;\n\n const isError = !!errorMessage;\n\n const sizeStyles = theme.sizing.textarea(size);\n const inputColors = theme.colors.control.input;\n\n const handleFocus = () => {\n if (!disabled) {\n setIsFocused(true);\n }\n onFocusProp?.();\n };\n\n const handleBlur = () => {\n if (!disabled) {\n setIsFocused(false);\n }\n onBlurProp?.();\n };\n\n let backgroundColor = inputColors.bg;\n let borderColor = inputColors.border;\n\n if (disabled) {\n backgroundColor = inputColors.bgDisable;\n borderColor = inputColors.borderDisable;\n } else if (isError) {\n borderColor = theme.colors.border.alert;\n } else if (isFocused) {\n backgroundColor = theme.colors.control.focus.bg;\n borderColor = inputColors.borderHover;\n }\n\n const textColor = disabled\n ? inputColors.textDisable\n : (textColorOverride ?? inputColors.text);\n const placeholderColor = inputColors.placeholder;\n\n const describedByIds: string[] = [];\n if (isError) {\n describedByIds.push(errorId);\n }\n if (ariaDescribedBy) {\n describedByIds.push(ariaDescribedBy);\n }\n const computedDescribedBy =\n describedByIds.length > 0 ? describedByIds.join(\" \") : undefined;\n\n const outlineColor =\n isFocused && !disabled ? theme.colors.border.brand : undefined;\n\n // Resizable when a resize mode or explicit min/max height is requested.\n // The native resize grip lives on the bordered container, so the whole\n // box grows and the inner textarea (height: 100%) follows.\n const isResizable =\n resize !== \"none\" || minHeight != null || maxHeight != null;\n\n const containerStyle: CSSProperties = {\n ...(isResizable ? { resize, overflow: \"hidden\" } : {}),\n ...(outlineColor\n ? { outline: `1px solid ${outlineColor}`, outlineOffset: \"-1px\" }\n : {}),\n };\n\n return (\n <Box flexDirection=\"column\" gap={8} width=\"100%\">\n <Box\n backgroundColor={backgroundColor}\n borderColor={borderColor}\n borderWidth={borderColor !== \"transparent\" ? 1 : 0}\n borderRadius={sizeStyles.radius}\n height={isResizable ? undefined : sizeStyles.height}\n minHeight={isResizable ? (minHeight ?? sizeStyles.height) : undefined}\n maxHeight={maxHeight}\n padding={paddingMap[size]}\n flexDirection=\"row\"\n alignItems=\"stretch\"\n gap={12}\n position=\"relative\"\n cursor={disabled ? \"not-allowed\" : \"text\"}\n style={containerStyle}\n hoverStyle={\n !disabled && !isFocused && !isError\n ? {\n backgroundColor: inputColors.bgHover,\n }\n : undefined\n }\n >\n <Box flex={1} height=\"auto\">\n <TextAreaPrimitive\n ref={ref}\n id={textareaId}\n value={value}\n placeholder={placeholder}\n onChangeText={onChangeText}\n onFocus={handleFocus}\n onBlur={handleBlur}\n disabled={disabled}\n color={textColor}\n fontSize={sizeStyles.fontSize}\n fontFamily={theme.fonts.body}\n placeholderTextColor={placeholderColor}\n aria-label={ariaLabel}\n aria-invalid={isError || undefined}\n aria-disabled={disabled || undefined}\n aria-describedby={computedDescribedBy}\n data-testid={testID}\n />\n </Box>\n </Box>\n\n {isError && (\n <Text\n id={errorId}\n role=\"alert\"\n color={theme.colors.content.alert.primary}\n fontSize={sizeStyles.fontSize - 2}\n >\n {errorMessage}\n </Text>\n )}\n </Box>\n );\n }\n);\n\nTextArea.displayName = \"TextArea\";\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n AccessibilityRole,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nconst roleToAccessibilityRole: Record<string, AccessibilityRole> = {\n button: \"button\",\n link: \"link\",\n img: \"image\",\n image: \"image\",\n summary: \"summary\",\n switch: \"switch\",\n checkbox: \"checkbox\",\n radio: \"radio\",\n heading: \"header\",\n text: \"text\",\n search: \"search\",\n alert: \"alert\",\n none: \"none\",\n presentation: \"none\",\n progressbar: \"progressbar\",\n scrollbar: \"scrollbar\",\n adjustable: \"adjustable\",\n tab: \"tab\",\n menu: \"menu\",\n menuitem: \"menuitem\",\n list: \"list\",\n timer: \"timer\",\n};\n\n/** RN ViewStyle.gap is typed as number (Yoga gap), not DimensionValue. */\nconst toGapValue = (gap: number | string | undefined): number | undefined => {\n if (gap === undefined) return undefined;\n if (typeof gap === \"number\") return gap;\n const pxMatch = /^(\\d+(?:\\.\\d+)?)px$/.exec(gap);\n if (pxMatch) return Number(pxMatch[1]);\n const asNumber = Number(gap);\n return Number.isFinite(asNumber) ? asNumber : undefined;\n};\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n flexWrap,\n alignItems,\n justifyContent,\n alignSelf,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n flexShrink,\n gap,\n overflow,\n opacity,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n disabled,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n opacity: opacity ?? (disabled ? 0.5 : undefined),\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n flexWrap,\n alignItems,\n justifyContent,\n alignSelf,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n flexShrink,\n gap: toGapValue(gap),\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Map web a11y props; drop the rest of the web-only attributes before\n // spreading onto RN hosts (unknown props warn at runtime).\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": ariaDisabled,\n \"aria-live\": ariaLive,\n \"aria-busy\": ariaBusy,\n className,\n \"data-testid\": _dataTestId,\n cursor: _cursor,\n type: _type,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n const accessibilityRole =\n (typeof role === \"string\" && roleToAccessibilityRole[role]) ||\n (as === \"button\" ? \"button\" : undefined);\n const isDisabled = Boolean(disabled || ariaDisabled);\n const accessibilityState = {\n disabled: isDisabled || undefined,\n busy: Boolean(ariaBusy) || undefined,\n };\n const accessibilityLiveRegion =\n ariaLive === \"polite\" || ariaLive === \"assertive\" ? ariaLive : undefined;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n accessibilityLabel={typeof ariaLabel === \"string\" ? ariaLabel : alt}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n // Prefer Pressable whenever the node is interactive or explicitly a button,\n // so disabled / aria-disabled controls stay in the a11y tree as buttons.\n if (onPress || as === \"button\") {\n return (\n <Pressable\n onPress={!isDisabled && onPress ? onPress : undefined}\n disabled={isDisabled}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n accessibilityRole={accessibilityRole}\n accessibilityLabel={\n typeof ariaLabel === \"string\" ? ariaLabel : undefined\n }\n accessibilityState={accessibilityState}\n accessibilityLiveRegion={accessibilityLiveRegion}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n accessibilityRole={accessibilityRole}\n accessibilityLabel={typeof ariaLabel === \"string\" ? ariaLabel : undefined}\n accessibilityState={accessibilityState}\n accessibilityLiveRegion={accessibilityLiveRegion}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import React from \"react\";\nimport {\n Text as RNText,\n TextStyle,\n AccessibilityRole,\n StyleSheet,\n} from \"react-native\";\nimport { TextProps } from \"@xsolla/xui-primitives-core\";\n\nconst roleMap: Record<string, AccessibilityRole> = {\n alert: \"alert\",\n heading: \"header\",\n button: \"button\",\n link: \"link\",\n text: \"text\",\n};\n\nconst parseNumericValue = (\n value: string | number | undefined\n): number | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === \"number\") return value;\n const parsed = parseFloat(value);\n return isNaN(parsed) ? undefined : parsed;\n};\n\nexport const Text: React.FC<TextProps> = ({\n children,\n color,\n fontSize,\n fontWeight,\n fontFamily,\n textAlign,\n lineHeight,\n numberOfLines,\n id,\n role,\n testID,\n \"data-testid\": dataTestId,\n style: styleProp,\n ...props\n}) => {\n let resolvedFontFamily = fontFamily\n ? fontFamily.split(\",\")[0].replace(/['\"]/g, \"\").trim()\n : undefined;\n\n if (\n resolvedFontFamily === \"Pilat Wide\" ||\n resolvedFontFamily === \"Pilat Wide Bold\" ||\n resolvedFontFamily === \"Aktiv Grotesk\"\n ) {\n resolvedFontFamily = undefined;\n }\n\n const incomingStyle = StyleSheet.flatten(styleProp) as TextStyle | undefined;\n\n const baseStyle: TextStyle = {\n color: color ?? incomingStyle?.color,\n fontSize: typeof fontSize === \"number\" ? fontSize : undefined,\n fontWeight: fontWeight as TextStyle[\"fontWeight\"],\n fontFamily: resolvedFontFamily,\n textDecorationLine: props.textDecoration as TextStyle[\"textDecorationLine\"],\n textAlign: textAlign ?? incomingStyle?.textAlign,\n lineHeight: parseNumericValue(lineHeight ?? incomingStyle?.lineHeight),\n marginTop: parseNumericValue(\n incomingStyle?.marginTop as number | string | undefined\n ),\n marginBottom: parseNumericValue(\n incomingStyle?.marginBottom as number | string | undefined\n ),\n };\n\n const accessibilityRole = role ? roleMap[role] : undefined;\n\n return (\n <RNText\n style={baseStyle}\n numberOfLines={numberOfLines}\n testID={dataTestId || testID || id}\n accessibilityRole={accessibilityRole}\n >\n {children}\n </RNText>\n );\n};\n","import React, { forwardRef } from \"react\";\nimport { TextInput as RNTextInput } from \"react-native\";\nimport { TextAreaPrimitiveProps } from \"@xsolla/xui-primitives-core\";\n\nexport const TextAreaPrimitive = forwardRef<\n RNTextInput,\n TextAreaPrimitiveProps\n>(\n (\n {\n value,\n placeholder,\n onChange,\n onChangeText,\n onFocus,\n onBlur,\n onKeyDown,\n disabled,\n readOnly,\n style,\n color,\n fontSize,\n fontFamily,\n placeholderTextColor,\n maxLength,\n rows,\n id,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-label\": ariaLabel,\n \"aria-disabled\": ariaDisabled,\n \"aria-invalid\": ariaInvalid,\n \"data-testid\": dataTestId,\n testID,\n },\n ref\n ) => {\n let resolvedFontFamily = fontFamily\n ? fontFamily.split(\",\")[0].replace(/['\"]/g, \"\").trim()\n : undefined;\n\n if (\n resolvedFontFamily === \"Pilat Wide\" ||\n resolvedFontFamily === \"Pilat Wide Bold\" ||\n resolvedFontFamily === \"Aktiv Grotesk\"\n ) {\n resolvedFontFamily = undefined;\n }\n\n const handleChangeText = (text: string) => {\n onChangeText?.(text);\n\n if (onChange) {\n const syntheticEvent = {\n target: { value: text },\n currentTarget: { value: text },\n type: \"change\",\n nativeEvent: { text },\n preventDefault: () => {},\n stopPropagation: () => {},\n isTrusted: false,\n } as unknown as React.ChangeEvent<HTMLTextAreaElement>;\n onChange(syntheticEvent);\n }\n };\n\n return (\n <RNTextInput\n ref={ref}\n value={value}\n placeholder={placeholder}\n onChangeText={handleChangeText}\n onFocus={onFocus}\n onBlur={onBlur}\n onKeyPress={(e) => {\n if (onKeyDown) {\n onKeyDown({\n key: e.nativeEvent.key,\n preventDefault: () => {},\n } as any);\n }\n }}\n editable={!disabled && !readOnly}\n multiline={true}\n numberOfLines={rows || 4}\n style={[\n {\n color,\n fontSize: typeof fontSize === \"number\" ? fontSize : undefined,\n fontFamily: resolvedFontFamily,\n flex: 1,\n padding: 0,\n textAlignVertical: \"top\",\n textAlign: (style as any)?.textAlign || \"left\",\n },\n style as any,\n ]}\n placeholderTextColor={placeholderTextColor}\n maxLength={maxLength}\n testID={dataTestId || testID || id}\n accessibilityLabel={ariaLabel}\n // RN AccessibilityState has no `invalid` / `readOnly`; surface via hint.\n accessibilityHint={\n [\n ariaInvalid ? \"Invalid\" : null,\n readOnly ? \"Read only\" : null,\n ariaDescribedBy,\n ]\n .filter(Boolean)\n .join(\". \") || undefined\n }\n accessibilityState={{\n disabled: disabled || ariaDisabled,\n }}\n accessible={true}\n />\n );\n }\n);\n\nTextAreaPrimitive.displayName = \"TextAreaPrimitive\";\n"],"mappings":"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","names":["import_react","import_react_native","import_jsx_runtime","RNText","import_react_native","import_jsx_runtime","RNTextInput","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../../src/index.tsx","../../src/TextArea.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../../../foundation/primitives-native/src/Text.tsx","../../../../foundation/primitives-native/src/TextArea.tsx"],"sourcesContent":["export * from \"./TextArea\";\n","import { useState, forwardRef, type CSSProperties } from \"react\";\nimport { Box, Text, TextAreaPrimitive } from \"@xsolla/xui-primitives\";\nimport {\n useResolvedTheme,\n useId,\n type ThemeOverrideProps,\n} from \"@xsolla/xui-core\";\n\nconst paddingMap: Record<string, number> = {\n xl: 16,\n lg: 14,\n md: 12,\n sm: 10,\n xs: 10,\n};\n\nexport interface TextAreaProps extends ThemeOverrideProps {\n /** Current value of the textarea */\n value?: string;\n /** Placeholder text when empty */\n placeholder?: string;\n /** Event handler when the text changes */\n onChangeText?: (text: string) => void;\n /** Callback fired when the textarea loses focus */\n onBlur?: () => void;\n /** Callback fired when the textarea gains focus */\n onFocus?: () => void;\n /** Size of the textarea */\n size?: \"xl\" | \"lg\" | \"md\" | \"sm\" | \"xs\";\n /** Minimum height of the textarea container, in pixels */\n minHeight?: number;\n /** Maximum height of the textarea container, in pixels */\n maxHeight?: number;\n /** Native resize grip behavior. Defaults to \"vertical\" */\n resize?: \"none\" | \"vertical\" | \"horizontal\" | \"both\";\n /** Override the resolved text color */\n textColor?: string;\n /** Whether the textarea is disabled */\n disabled?: boolean;\n /**\n * Validation state driving the border highlight, independent of any message.\n *\n * Use this when the message is rendered elsewhere (a form-level summary, a\n * sibling label) but the field itself still needs to be highlighted. Passing\n * `errorMessage` or `warningMessage` implies the matching state, so you only\n * need `state` for the message-less case.\n *\n * `\"error\"` takes precedence over `\"warning\"`.\n *\n * Defaults to `\"default\"`.\n */\n state?: \"default\" | \"warning\" | \"error\";\n /** Error message displayed below the textarea. Implies `state=\"error\"` */\n errorMessage?: string;\n /**\n * Warning message displayed below the textarea. Implies `state=\"warning\"`.\n *\n * A warning is for input that is permitted but undesirable (e.g. an empty\n * optional field the user probably meant to fill in). Unlike an error it does\n * not mark the field invalid, so it is announced politely rather than\n * assertively. Ignored when the textarea is in the error state.\n */\n warningMessage?: string;\n /** Accessible label for screen readers */\n \"aria-label\"?: string;\n /** ID of element that describes this textarea */\n \"aria-describedby\"?: string;\n /** Unique identifier for the textarea element */\n id?: string;\n testID?: string;\n}\n\n/**\n * TextArea - An accessible multi-line text input component\n *\n * Renders as a semantic `<textarea>` element with full ARIA support.\n * Supports labels, error and warning states, and various sizes.\n *\n * ## Validation states\n *\n * - **Error** — blocking. Set `errorMessage`, or `state=\"error\"` to highlight\n * the border only. Marks the field `aria-invalid` and announces the message\n * assertively via `role=\"alert\"`.\n * - **Warning** — non-blocking, \"needs attention\". Set `warningMessage`, or\n * `state=\"warning\"` to highlight the border only. Does *not* mark the field\n * invalid; the message is announced politely via `role=\"status\"`.\n *\n * Error wins when both are supplied.\n *\n * ## Accessibility Features\n *\n * - **Semantic HTML**: Renders as a native `<textarea>` element\n * - **Keyboard Navigation**: Focusable via Tab\n * - **ARIA States**: Properly announces disabled and error states\n * - **Error Announcements**: Error messages use `role=\"alert\"` for immediate announcement\n * - **Warning Announcements**: Warning messages use `role=\"status\"` so they are\n * announced politely without interrupting the user\n * - **Focus Indicator**: Visible focus ring for keyboard navigation\n *\n */\nexport const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(\n (\n {\n value,\n placeholder,\n onChangeText,\n onBlur: onBlurProp,\n onFocus: onFocusProp,\n size = \"md\",\n minHeight,\n maxHeight,\n resize = \"vertical\",\n textColor: textColorOverride,\n disabled = false,\n state = \"default\",\n errorMessage,\n warningMessage,\n \"aria-label\": ariaLabel,\n \"aria-describedby\": ariaDescribedBy,\n id: externalId,\n testID,\n themeMode,\n themeProductContext,\n },\n ref\n ) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const [isFocused, setIsFocused] = useState(false);\n\n const generatedId = useId();\n const textareaId = externalId || generatedId;\n const errorId = `${textareaId}-error`;\n const warningId = `${textareaId}-warning`;\n\n // A message implies its state, so callers only need `state` when they want\n // the border highlight without any message. Error always wins.\n const isError = state === \"error\" || !!errorMessage;\n const isWarning =\n !isError && (state === \"warning\" || !!warningMessage);\n\n const showErrorMessage = isError && !!errorMessage;\n const showWarningMessage = isWarning && !!warningMessage;\n\n const sizeStyles = theme.sizing.textarea(size);\n const inputColors = theme.colors.control.input;\n\n const handleFocus = () => {\n if (!disabled) {\n setIsFocused(true);\n }\n onFocusProp?.();\n };\n\n const handleBlur = () => {\n if (!disabled) {\n setIsFocused(false);\n }\n onBlurProp?.();\n };\n\n let backgroundColor = inputColors.bg;\n let borderColor = inputColors.border;\n\n if (disabled) {\n backgroundColor = inputColors.bgDisable;\n borderColor = inputColors.borderDisable;\n } else if (isError) {\n borderColor = theme.colors.border.alert;\n } else if (isWarning) {\n borderColor = theme.colors.border.warning;\n } else if (isFocused) {\n backgroundColor = theme.colors.control.focus.bg;\n borderColor = inputColors.borderHover;\n }\n\n const textColor = disabled\n ? inputColors.textDisable\n : (textColorOverride ?? inputColors.text);\n const placeholderColor = inputColors.placeholder;\n\n const describedByIds: string[] = [];\n if (showErrorMessage) {\n describedByIds.push(errorId);\n }\n if (showWarningMessage) {\n describedByIds.push(warningId);\n }\n if (ariaDescribedBy) {\n describedByIds.push(ariaDescribedBy);\n }\n const computedDescribedBy =\n describedByIds.length > 0 ? describedByIds.join(\" \") : undefined;\n\n const outlineColor =\n isFocused && !disabled ? theme.colors.border.brand : undefined;\n\n // Resizable when a resize mode or explicit min/max height is requested.\n // The native resize grip lives on the bordered container, so the whole\n // box grows and the inner textarea (height: 100%) follows.\n const isResizable =\n resize !== \"none\" || minHeight != null || maxHeight != null;\n\n const containerStyle: CSSProperties = {\n ...(isResizable ? { resize, overflow: \"hidden\" } : {}),\n ...(outlineColor\n ? { outline: `1px solid ${outlineColor}`, outlineOffset: \"-1px\" }\n : {}),\n };\n\n return (\n <Box flexDirection=\"column\" gap={8} width=\"100%\">\n <Box\n backgroundColor={backgroundColor}\n borderColor={borderColor}\n borderWidth={borderColor !== \"transparent\" ? 1 : 0}\n borderRadius={sizeStyles.radius}\n height={isResizable ? undefined : sizeStyles.height}\n minHeight={isResizable ? (minHeight ?? sizeStyles.height) : undefined}\n maxHeight={maxHeight}\n padding={paddingMap[size]}\n flexDirection=\"row\"\n alignItems=\"stretch\"\n gap={12}\n position=\"relative\"\n cursor={disabled ? \"not-allowed\" : \"text\"}\n style={containerStyle}\n hoverStyle={\n !disabled && !isFocused && !isError && !isWarning\n ? {\n backgroundColor: inputColors.bgHover,\n }\n : undefined\n }\n >\n <Box flex={1} height=\"auto\">\n <TextAreaPrimitive\n ref={ref}\n id={textareaId}\n value={value}\n placeholder={placeholder}\n onChangeText={onChangeText}\n onFocus={handleFocus}\n onBlur={handleBlur}\n disabled={disabled}\n color={textColor}\n fontSize={sizeStyles.fontSize}\n fontFamily={theme.fonts.body}\n placeholderTextColor={placeholderColor}\n aria-label={ariaLabel}\n aria-invalid={isError || undefined}\n aria-disabled={disabled || undefined}\n aria-describedby={computedDescribedBy}\n data-testid={testID}\n />\n </Box>\n </Box>\n\n {showErrorMessage && (\n <Text\n id={errorId}\n role=\"alert\"\n color={theme.colors.content.alert.primary}\n fontSize={sizeStyles.fontSize - 2}\n >\n {errorMessage}\n </Text>\n )}\n\n {showWarningMessage && (\n <Text\n id={warningId}\n role=\"status\"\n color={theme.colors.content.warning.primary}\n fontSize={sizeStyles.fontSize - 2}\n >\n {warningMessage}\n </Text>\n )}\n </Box>\n );\n }\n);\n\nTextArea.displayName = \"TextArea\";\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n AccessibilityRole,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nconst roleToAccessibilityRole: Record<string, AccessibilityRole> = {\n button: \"button\",\n link: \"link\",\n img: \"image\",\n image: \"image\",\n summary: \"summary\",\n switch: \"switch\",\n checkbox: \"checkbox\",\n radio: \"radio\",\n heading: \"header\",\n text: \"text\",\n search: \"search\",\n alert: \"alert\",\n none: \"none\",\n presentation: \"none\",\n progressbar: \"progressbar\",\n scrollbar: \"scrollbar\",\n adjustable: \"adjustable\",\n tab: \"tab\",\n menu: \"menu\",\n menuitem: \"menuitem\",\n list: \"list\",\n timer: \"timer\",\n};\n\n/** RN ViewStyle.gap is typed as number (Yoga gap), not DimensionValue. */\nconst toGapValue = (gap: number | string | undefined): number | undefined => {\n if (gap === undefined) return undefined;\n if (typeof gap === \"number\") return gap;\n const pxMatch = /^(\\d+(?:\\.\\d+)?)px$/.exec(gap);\n if (pxMatch) return Number(pxMatch[1]);\n const asNumber = Number(gap);\n return Number.isFinite(asNumber) ? asNumber : undefined;\n};\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n flexWrap,\n alignItems,\n justifyContent,\n alignSelf,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n flexShrink,\n gap,\n overflow,\n opacity,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n disabled,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n opacity: opacity ?? (disabled ? 0.5 : undefined),\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n flexWrap,\n alignItems,\n justifyContent,\n alignSelf,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n flexShrink,\n gap: toGapValue(gap),\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Map web a11y props; drop the rest of the web-only attributes before\n // spreading onto RN hosts (unknown props warn at runtime).\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": ariaDisabled,\n \"aria-live\": ariaLive,\n \"aria-busy\": ariaBusy,\n className,\n \"data-testid\": _dataTestId,\n cursor: _cursor,\n type: _type,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n const accessibilityRole =\n (typeof role === \"string\" && roleToAccessibilityRole[role]) ||\n (as === \"button\" ? \"button\" : undefined);\n const isDisabled = Boolean(disabled || ariaDisabled);\n const accessibilityState = {\n disabled: isDisabled || undefined,\n busy: Boolean(ariaBusy) || undefined,\n };\n const accessibilityLiveRegion =\n ariaLive === \"polite\" || ariaLive === \"assertive\" ? ariaLive : undefined;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n accessibilityLabel={typeof ariaLabel === \"string\" ? ariaLabel : alt}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n // Prefer Pressable whenever the node is interactive or explicitly a button,\n // so disabled / aria-disabled controls stay in the a11y tree as buttons.\n if (onPress || as === \"button\") {\n return (\n <Pressable\n onPress={!isDisabled && onPress ? onPress : undefined}\n disabled={isDisabled}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n accessibilityRole={accessibilityRole}\n accessibilityLabel={\n typeof ariaLabel === \"string\" ? ariaLabel : undefined\n }\n accessibilityState={accessibilityState}\n accessibilityLiveRegion={accessibilityLiveRegion}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n accessibilityRole={accessibilityRole}\n accessibilityLabel={typeof ariaLabel === \"string\" ? ariaLabel : undefined}\n accessibilityState={accessibilityState}\n accessibilityLiveRegion={accessibilityLiveRegion}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import React from \"react\";\nimport {\n Text as RNText,\n TextStyle,\n AccessibilityRole,\n StyleSheet,\n} from \"react-native\";\nimport { TextProps } from \"@xsolla/xui-primitives-core\";\n\nconst roleMap: Record<string, AccessibilityRole> = {\n alert: \"alert\",\n heading: \"header\",\n button: \"button\",\n link: \"link\",\n text: \"text\",\n};\n\nconst parseNumericValue = (\n value: string | number | undefined\n): number | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === \"number\") return value;\n const parsed = parseFloat(value);\n return isNaN(parsed) ? undefined : parsed;\n};\n\nexport const Text: React.FC<TextProps> = ({\n children,\n color,\n fontSize,\n fontWeight,\n fontFamily,\n textAlign,\n lineHeight,\n numberOfLines,\n id,\n role,\n testID,\n \"data-testid\": dataTestId,\n style: styleProp,\n ...props\n}) => {\n let resolvedFontFamily = fontFamily\n ? fontFamily.split(\",\")[0].replace(/['\"]/g, \"\").trim()\n : undefined;\n\n if (\n resolvedFontFamily === \"Pilat Wide\" ||\n resolvedFontFamily === \"Pilat Wide Bold\" ||\n resolvedFontFamily === \"Aktiv Grotesk\"\n ) {\n resolvedFontFamily = undefined;\n }\n\n const incomingStyle = StyleSheet.flatten(styleProp) as TextStyle | undefined;\n\n const baseStyle: TextStyle = {\n color: color ?? incomingStyle?.color,\n fontSize: typeof fontSize === \"number\" ? fontSize : undefined,\n fontWeight: fontWeight as TextStyle[\"fontWeight\"],\n fontFamily: resolvedFontFamily,\n textDecorationLine: props.textDecoration as TextStyle[\"textDecorationLine\"],\n textAlign: textAlign ?? incomingStyle?.textAlign,\n lineHeight: parseNumericValue(lineHeight ?? incomingStyle?.lineHeight),\n marginTop: parseNumericValue(\n incomingStyle?.marginTop as number | string | undefined\n ),\n marginBottom: parseNumericValue(\n incomingStyle?.marginBottom as number | string | undefined\n ),\n };\n\n const accessibilityRole = role ? roleMap[role] : undefined;\n\n return (\n <RNText\n style={baseStyle}\n numberOfLines={numberOfLines}\n testID={dataTestId || testID || id}\n accessibilityRole={accessibilityRole}\n >\n {children}\n </RNText>\n );\n};\n","import React, { forwardRef } from \"react\";\nimport { TextInput as RNTextInput } from \"react-native\";\nimport { TextAreaPrimitiveProps } from \"@xsolla/xui-primitives-core\";\n\nexport const TextAreaPrimitive = forwardRef<\n RNTextInput,\n TextAreaPrimitiveProps\n>(\n (\n {\n value,\n placeholder,\n onChange,\n onChangeText,\n onFocus,\n onBlur,\n onKeyDown,\n disabled,\n readOnly,\n style,\n color,\n fontSize,\n fontFamily,\n placeholderTextColor,\n maxLength,\n rows,\n id,\n \"aria-describedby\": ariaDescribedBy,\n \"aria-label\": ariaLabel,\n \"aria-disabled\": ariaDisabled,\n \"aria-invalid\": ariaInvalid,\n \"data-testid\": dataTestId,\n testID,\n },\n ref\n ) => {\n let resolvedFontFamily = fontFamily\n ? fontFamily.split(\",\")[0].replace(/['\"]/g, \"\").trim()\n : undefined;\n\n if (\n resolvedFontFamily === \"Pilat Wide\" ||\n resolvedFontFamily === \"Pilat Wide Bold\" ||\n resolvedFontFamily === \"Aktiv Grotesk\"\n ) {\n resolvedFontFamily = undefined;\n }\n\n const handleChangeText = (text: string) => {\n onChangeText?.(text);\n\n if (onChange) {\n const syntheticEvent = {\n target: { value: text },\n currentTarget: { value: text },\n type: \"change\",\n nativeEvent: { text },\n preventDefault: () => {},\n stopPropagation: () => {},\n isTrusted: false,\n } as unknown as React.ChangeEvent<HTMLTextAreaElement>;\n onChange(syntheticEvent);\n }\n };\n\n return (\n <RNTextInput\n ref={ref}\n value={value}\n placeholder={placeholder}\n onChangeText={handleChangeText}\n onFocus={onFocus}\n onBlur={onBlur}\n onKeyPress={(e) => {\n if (onKeyDown) {\n onKeyDown({\n key: e.nativeEvent.key,\n preventDefault: () => {},\n } as any);\n }\n }}\n editable={!disabled && !readOnly}\n multiline={true}\n numberOfLines={rows || 4}\n style={[\n {\n color,\n fontSize: typeof fontSize === \"number\" ? fontSize : undefined,\n fontFamily: resolvedFontFamily,\n flex: 1,\n padding: 0,\n textAlignVertical: \"top\",\n textAlign: (style as any)?.textAlign || \"left\",\n },\n style as any,\n ]}\n placeholderTextColor={placeholderTextColor}\n maxLength={maxLength}\n testID={dataTestId || testID || id}\n accessibilityLabel={ariaLabel}\n // RN AccessibilityState has no `invalid` / `readOnly`; surface via hint.\n accessibilityHint={\n [\n ariaInvalid ? \"Invalid\" : null,\n readOnly ? \"Read only\" : null,\n ariaDescribedBy,\n ]\n .filter(Boolean)\n .join(\". \") || undefined\n }\n accessibilityState={{\n disabled: disabled || ariaDisabled,\n }}\n accessible={true}\n />\n );\n }\n);\n\nTextAreaPrimitive.displayName = \"TextAreaPrimitive\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,gBAAyD;;;ACCzD,0BASO;AAwMD;AArMN,IAAM,0BAA6D;AAAA,EACjE,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,KAAK;AAAA,EACL,OAAO;AAAA,EACP,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,OAAO;AAAA,EACP,SAAS;AAAA,EACT,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,cAAc;AAAA,EACd,aAAa;AAAA,EACb,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,MAAM;AAAA,EACN,UAAU;AAAA,EACV,MAAM;AAAA,EACN,OAAO;AACT;AAGA,IAAM,aAAa,CAAC,QAAyD;AAC3E,MAAI,QAAQ,OAAW,QAAO;AAC9B,MAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,QAAM,UAAU,sBAAsB,KAAK,GAAG;AAC9C,MAAI,QAAS,QAAO,OAAO,QAAQ,CAAC,CAAC;AACrC,QAAM,WAAW,OAAO,GAAG;AAC3B,SAAO,OAAO,SAAS,QAAQ,IAAI,WAAW;AAChD;AAEO,IAAM,MAA0B,CAAC;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAM;AACJ,QAAM,oBAAoB,CAAC,aAAkC;AAAA,IAC3D,iBACE,WAAW,YAAY,kBACnB,WAAW,kBACX;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,YAAY,WAAW,MAAM;AAAA,IACtC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,KAAK,WAAW,GAAG;AAAA,IACnB,GAAI;AAAA,EACN;AAEA,QAAM,cAAc,cAAc;AAKlC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,aAAa;AAAA,IACb,aAAa;AAAA,IACb;AAAA,IACA,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,GAAG;AAAA,EACL,IAAI;AAEJ,QAAM,oBACH,OAAO,SAAS,YAAY,wBAAwB,IAAI,MACxD,OAAO,WAAW,WAAW;AAChC,QAAM,aAAa,QAAQ,YAAY,YAAY;AACnD,QAAM,qBAAqB;AAAA,IACzB,UAAU,cAAc;AAAA,IACxB,MAAM,QAAQ,QAAQ,KAAK;AAAA,EAC7B;AACA,QAAM,0BACJ,aAAa,YAAY,aAAa,cAAc,WAAW;AAGjE,MAAI,OAAO,SAAS,KAAK;AACvB,UAAM,aAAyB;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAI;AAAA,IACN;AAEA,WACE;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ,EAAE,KAAK,IAAI;AAAA,QACnB,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,oBAAoB,OAAO,cAAc,WAAW,YAAY;AAAA,QAChE,YAAW;AAAA,QACV,GAAG;AAAA;AAAA,IACN;AAAA,EAEJ;AAIA,MAAI,WAAW,OAAO,UAAU;AAC9B,WACE;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,CAAC,cAAc,UAAU,UAAU;AAAA,QAC5C,UAAU;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,CAAC,EAAE,QAAQ,MAAM,kBAAkB,OAAO;AAAA,QACjD,QAAQ;AAAA,QACR;AAAA,QACA,oBACE,OAAO,cAAc,WAAW,YAAY;AAAA,QAE9C;AAAA,QACA;AAAA,QACC,GAAG;AAAA,QAEH;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,kBAAkB;AAAA,MACzB,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,oBAAoB,OAAO,cAAc,WAAW,YAAY;AAAA,MAChE;AAAA,MACA;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ;;;AC3QA,IAAAC,uBAKO;AAqEH,IAAAC,sBAAA;AAlEJ,IAAM,UAA6C;AAAA,EACjD,OAAO;AAAA,EACP,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AACR;AAEA,IAAM,oBAAoB,CACxB,UACuB;AACvB,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,SAAS,WAAW,KAAK;AAC/B,SAAO,MAAM,MAAM,IAAI,SAAY;AACrC;AAEO,IAAM,OAA4B,CAAC;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,OAAO;AAAA,EACP,GAAG;AACL,MAAM;AACJ,MAAI,qBAAqB,aACrB,WAAW,MAAM,GAAG,EAAE,CAAC,EAAE,QAAQ,SAAS,EAAE,EAAE,KAAK,IACnD;AAEJ,MACE,uBAAuB,gBACvB,uBAAuB,qBACvB,uBAAuB,iBACvB;AACA,yBAAqB;AAAA,EACvB;AAEA,QAAM,gBAAgB,gCAAW,QAAQ,SAAS;AAElD,QAAM,YAAuB;AAAA,IAC3B,OAAO,SAAS,eAAe;AAAA,IAC/B,UAAU,OAAO,aAAa,WAAW,WAAW;AAAA,IACpD;AAAA,IACA,YAAY;AAAA,IACZ,oBAAoB,MAAM;AAAA,IAC1B,WAAW,aAAa,eAAe;AAAA,IACvC,YAAY,kBAAkB,cAAc,eAAe,UAAU;AAAA,IACrE,WAAW;AAAA,MACT,eAAe;AAAA,IACjB;AAAA,IACA,cAAc;AAAA,MACZ,eAAe;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,oBAAoB,OAAO,QAAQ,IAAI,IAAI;AAEjD,SACE;AAAA,IAAC,qBAAAC;AAAA,IAAA;AAAA,MACC,OAAO;AAAA,MACP;AAAA,MACA,QAAQ,cAAc,UAAU;AAAA,MAChC;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;;;ACpFA,mBAAkC;AAClC,IAAAC,uBAAyC;AAiEnC,IAAAC,sBAAA;AA9DC,IAAM,wBAAoB;AAAA,EAI/B,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB;AAAA,IACpB,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf;AAAA,EACF,GACA,QACG;AACH,QAAI,qBAAqB,aACrB,WAAW,MAAM,GAAG,EAAE,CAAC,EAAE,QAAQ,SAAS,EAAE,EAAE,KAAK,IACnD;AAEJ,QACE,uBAAuB,gBACvB,uBAAuB,qBACvB,uBAAuB,iBACvB;AACA,2BAAqB;AAAA,IACvB;AAEA,UAAM,mBAAmB,CAAC,SAAiB;AACzC,qBAAe,IAAI;AAEnB,UAAI,UAAU;AACZ,cAAM,iBAAiB;AAAA,UACrB,QAAQ,EAAE,OAAO,KAAK;AAAA,UACtB,eAAe,EAAE,OAAO,KAAK;AAAA,UAC7B,MAAM;AAAA,UACN,aAAa,EAAE,KAAK;AAAA,UACpB,gBAAgB,MAAM;AAAA,UAAC;AAAA,UACvB,iBAAiB,MAAM;AAAA,UAAC;AAAA,UACxB,WAAW;AAAA,QACb;AACA,iBAAS,cAAc;AAAA,MACzB;AAAA,IACF;AAEA,WACE;AAAA,MAAC,qBAAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA,cAAc;AAAA,QACd;AAAA,QACA;AAAA,QACA,YAAY,CAAC,MAAM;AACjB,cAAI,WAAW;AACb,sBAAU;AAAA,cACR,KAAK,EAAE,YAAY;AAAA,cACnB,gBAAgB,MAAM;AAAA,cAAC;AAAA,YACzB,CAAQ;AAAA,UACV;AAAA,QACF;AAAA,QACA,UAAU,CAAC,YAAY,CAAC;AAAA,QACxB,WAAW;AAAA,QACX,eAAe,QAAQ;AAAA,QACvB,OAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,UAAU,OAAO,aAAa,WAAW,WAAW;AAAA,YACpD,YAAY;AAAA,YACZ,MAAM;AAAA,YACN,SAAS;AAAA,YACT,mBAAmB;AAAA,YACnB,WAAY,OAAe,aAAa;AAAA,UAC1C;AAAA,UACA;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ,cAAc,UAAU;AAAA,QAChC,oBAAoB;AAAA,QAEpB,mBACE;AAAA,UACE,cAAc,YAAY;AAAA,UAC1B,WAAW,cAAc;AAAA,UACzB;AAAA,QACF,EACG,OAAO,OAAO,EACd,KAAK,IAAI,KAAK;AAAA,QAEnB,oBAAoB;AAAA,UAClB,UAAU,YAAY;AAAA,QACxB;AAAA,QACA,YAAY;AAAA;AAAA,IACd;AAAA,EAEJ;AACF;AAEA,kBAAkB,cAAc;;;AHrHhC,sBAIO;AA4MD,IAAAC,sBAAA;AA1MN,IAAM,aAAqC;AAAA,EACzC,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAsFO,IAAM,eAAW;AAAA,EACtB,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT,WAAW;AAAA,IACX,WAAW;AAAA,IACX,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,IAAI;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,EACF,GACA,QACG;AACH,UAAM,EAAE,MAAM,QAAI,kCAAiB,EAAE,WAAW,oBAAoB,CAAC;AACrE,UAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,KAAK;AAEhD,UAAM,kBAAc,uBAAM;AAC1B,UAAM,aAAa,cAAc;AACjC,UAAM,UAAU,GAAG,UAAU;AAC7B,UAAM,YAAY,GAAG,UAAU;AAI/B,UAAM,UAAU,UAAU,WAAW,CAAC,CAAC;AACvC,UAAM,YACJ,CAAC,YAAY,UAAU,aAAa,CAAC,CAAC;AAExC,UAAM,mBAAmB,WAAW,CAAC,CAAC;AACtC,UAAM,qBAAqB,aAAa,CAAC,CAAC;AAE1C,UAAM,aAAa,MAAM,OAAO,SAAS,IAAI;AAC7C,UAAM,cAAc,MAAM,OAAO,QAAQ;AAEzC,UAAM,cAAc,MAAM;AACxB,UAAI,CAAC,UAAU;AACb,qBAAa,IAAI;AAAA,MACnB;AACA,oBAAc;AAAA,IAChB;AAEA,UAAM,aAAa,MAAM;AACvB,UAAI,CAAC,UAAU;AACb,qBAAa,KAAK;AAAA,MACpB;AACA,mBAAa;AAAA,IACf;AAEA,QAAI,kBAAkB,YAAY;AAClC,QAAI,cAAc,YAAY;AAE9B,QAAI,UAAU;AACZ,wBAAkB,YAAY;AAC9B,oBAAc,YAAY;AAAA,IAC5B,WAAW,SAAS;AAClB,oBAAc,MAAM,OAAO,OAAO;AAAA,IACpC,WAAW,WAAW;AACpB,oBAAc,MAAM,OAAO,OAAO;AAAA,IACpC,WAAW,WAAW;AACpB,wBAAkB,MAAM,OAAO,QAAQ,MAAM;AAC7C,oBAAc,YAAY;AAAA,IAC5B;AAEA,UAAM,YAAY,WACd,YAAY,cACX,qBAAqB,YAAY;AACtC,UAAM,mBAAmB,YAAY;AAErC,UAAM,iBAA2B,CAAC;AAClC,QAAI,kBAAkB;AACpB,qBAAe,KAAK,OAAO;AAAA,IAC7B;AACA,QAAI,oBAAoB;AACtB,qBAAe,KAAK,SAAS;AAAA,IAC/B;AACA,QAAI,iBAAiB;AACnB,qBAAe,KAAK,eAAe;AAAA,IACrC;AACA,UAAM,sBACJ,eAAe,SAAS,IAAI,eAAe,KAAK,GAAG,IAAI;AAEzD,UAAM,eACJ,aAAa,CAAC,WAAW,MAAM,OAAO,OAAO,QAAQ;AAKvD,UAAM,cACJ,WAAW,UAAU,aAAa,QAAQ,aAAa;AAEzD,UAAM,iBAAgC;AAAA,MACpC,GAAI,cAAc,EAAE,QAAQ,UAAU,SAAS,IAAI,CAAC;AAAA,MACpD,GAAI,eACA,EAAE,SAAS,aAAa,YAAY,IAAI,eAAe,OAAO,IAC9D,CAAC;AAAA,IACP;AAEA,WACE,8CAAC,OAAI,eAAc,UAAS,KAAK,GAAG,OAAM,QACxC;AAAA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA,aAAa,gBAAgB,gBAAgB,IAAI;AAAA,UACjD,cAAc,WAAW;AAAA,UACzB,QAAQ,cAAc,SAAY,WAAW;AAAA,UAC7C,WAAW,cAAe,aAAa,WAAW,SAAU;AAAA,UAC5D;AAAA,UACA,SAAS,WAAW,IAAI;AAAA,UACxB,eAAc;AAAA,UACd,YAAW;AAAA,UACX,KAAK;AAAA,UACL,UAAS;AAAA,UACT,QAAQ,WAAW,gBAAgB;AAAA,UACnC,OAAO;AAAA,UACP,YACE,CAAC,YAAY,CAAC,aAAa,CAAC,WAAW,CAAC,YACpC;AAAA,YACE,iBAAiB,YAAY;AAAA,UAC/B,IACA;AAAA,UAGN,uDAAC,OAAI,MAAM,GAAG,QAAO,QACnB;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA,IAAI;AAAA,cACJ;AAAA,cACA;AAAA,cACA;AAAA,cACA,SAAS;AAAA,cACT,QAAQ;AAAA,cACR;AAAA,cACA,OAAO;AAAA,cACP,UAAU,WAAW;AAAA,cACrB,YAAY,MAAM,MAAM;AAAA,cACxB,sBAAsB;AAAA,cACtB,cAAY;AAAA,cACZ,gBAAc,WAAW;AAAA,cACzB,iBAAe,YAAY;AAAA,cAC3B,oBAAkB;AAAA,cAClB,eAAa;AAAA;AAAA,UACf,GACF;AAAA;AAAA,MACF;AAAA,MAEC,oBACC;AAAA,QAAC;AAAA;AAAA,UACC,IAAI;AAAA,UACJ,MAAK;AAAA,UACL,OAAO,MAAM,OAAO,QAAQ,MAAM;AAAA,UAClC,UAAU,WAAW,WAAW;AAAA,UAE/B;AAAA;AAAA,MACH;AAAA,MAGD,sBACC;AAAA,QAAC;AAAA;AAAA,UACC,IAAI;AAAA,UACJ,MAAK;AAAA,UACL,OAAO,MAAM,OAAO,QAAQ,QAAQ;AAAA,UACpC,UAAU,WAAW,WAAW;AAAA,UAE/B;AAAA;AAAA,MACH;AAAA,OAEJ;AAAA,EAEJ;AACF;AAEA,SAAS,cAAc;","names":["import_react","import_react_native","import_jsx_runtime","RNText","import_react_native","import_jsx_runtime","RNTextInput","import_jsx_runtime"]}
package/native/index.mjs CHANGED
@@ -439,7 +439,9 @@ var TextArea = forwardRef2(
439
439
  resize = "vertical",
440
440
  textColor: textColorOverride,
441
441
  disabled = false,
442
+ state = "default",
442
443
  errorMessage,
444
+ warningMessage,
443
445
  "aria-label": ariaLabel,
444
446
  "aria-describedby": ariaDescribedBy,
445
447
  id: externalId,
@@ -452,7 +454,11 @@ var TextArea = forwardRef2(
452
454
  const generatedId = useId();
453
455
  const textareaId = externalId || generatedId;
454
456
  const errorId = `${textareaId}-error`;
455
- const isError = !!errorMessage;
457
+ const warningId = `${textareaId}-warning`;
458
+ const isError = state === "error" || !!errorMessage;
459
+ const isWarning = !isError && (state === "warning" || !!warningMessage);
460
+ const showErrorMessage = isError && !!errorMessage;
461
+ const showWarningMessage = isWarning && !!warningMessage;
456
462
  const sizeStyles = theme.sizing.textarea(size);
457
463
  const inputColors = theme.colors.control.input;
458
464
  const handleFocus = () => {
@@ -474,6 +480,8 @@ var TextArea = forwardRef2(
474
480
  borderColor = inputColors.borderDisable;
475
481
  } else if (isError) {
476
482
  borderColor = theme.colors.border.alert;
483
+ } else if (isWarning) {
484
+ borderColor = theme.colors.border.warning;
477
485
  } else if (isFocused) {
478
486
  backgroundColor = theme.colors.control.focus.bg;
479
487
  borderColor = inputColors.borderHover;
@@ -481,9 +489,12 @@ var TextArea = forwardRef2(
481
489
  const textColor = disabled ? inputColors.textDisable : textColorOverride ?? inputColors.text;
482
490
  const placeholderColor = inputColors.placeholder;
483
491
  const describedByIds = [];
484
- if (isError) {
492
+ if (showErrorMessage) {
485
493
  describedByIds.push(errorId);
486
494
  }
495
+ if (showWarningMessage) {
496
+ describedByIds.push(warningId);
497
+ }
487
498
  if (ariaDescribedBy) {
488
499
  describedByIds.push(ariaDescribedBy);
489
500
  }
@@ -512,7 +523,7 @@ var TextArea = forwardRef2(
512
523
  position: "relative",
513
524
  cursor: disabled ? "not-allowed" : "text",
514
525
  style: containerStyle,
515
- hoverStyle: !disabled && !isFocused && !isError ? {
526
+ hoverStyle: !disabled && !isFocused && !isError && !isWarning ? {
516
527
  backgroundColor: inputColors.bgHover
517
528
  } : void 0,
518
529
  children: /* @__PURE__ */ jsx4(Box, { flex: 1, height: "auto", children: /* @__PURE__ */ jsx4(
@@ -539,7 +550,7 @@ var TextArea = forwardRef2(
539
550
  ) })
540
551
  }
541
552
  ),
542
- isError && /* @__PURE__ */ jsx4(
553
+ showErrorMessage && /* @__PURE__ */ jsx4(
543
554
  Text,
544
555
  {
545
556
  id: errorId,
@@ -548,6 +559,16 @@ var TextArea = forwardRef2(
548
559
  fontSize: sizeStyles.fontSize - 2,
549
560
  children: errorMessage
550
561
  }
562
+ ),
563
+ showWarningMessage && /* @__PURE__ */ jsx4(
564
+ Text,
565
+ {
566
+ id: warningId,
567
+ role: "status",
568
+ color: theme.colors.content.warning.primary,
569
+ fontSize: sizeStyles.fontSize - 2,
570
+ children: warningMessage
571
+ }
551
572
  )
552
573
  ] });
553
574
  }