@xsolla/xui-input-edit 0.176.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 ADDED
@@ -0,0 +1,164 @@
1
+ # Input Edit
2
+
3
+ A multi-line text field for editing freeform text — comments, messages, notes — with inline (click-to-edit) and form (always-editable) modes; the field grows with its content. Works on web and React Native via `XUIProvider` themed contexts.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @xsolla/xui-input-edit
9
+ ```
10
+
11
+ ## Imports
12
+
13
+ ```tsx
14
+ import { InputEdit } from '@xsolla/xui-input-edit';
15
+ import type { InputEditProps } from '@xsolla/xui-input-edit';
16
+ ```
17
+
18
+ ## Quick start
19
+
20
+ ```tsx
21
+ const [value, setValue] = useState('Input text');
22
+
23
+ <InputEdit
24
+ value={value}
25
+ onChangeText={setValue}
26
+ onConfirm={(v) => save(v)}
27
+ />;
28
+ ```
29
+
30
+ ## API Reference
31
+
32
+ ### `<InputEdit>`
33
+
34
+ | Prop | Type | Default | Description |
35
+ | --- | --- | --- | --- |
36
+ | `value` | `string` | — | Controlled value. |
37
+ | `defaultValue` | `string` | `''` | Initial value for uncontrolled usage. |
38
+ | `placeholder` | `string` | `'Placeholder'` | Placeholder shown when empty. |
39
+ | `onChangeText` | `(text: string) => void` | — | Change handler receiving the current text (HTML when `richText` is set). |
40
+ | `onConfirm` | `(value: string) => void` | — | Called on confirm — check button, `Cmd`/`Ctrl` + `Enter`, or commit-on-blur (only when the value changed). |
41
+ | `onCancel` | `() => void` | — | Called on cancel (cross button or `Escape`); reverts to the last committed value. |
42
+ | `mode` | `'inline' \| 'form'` | `'inline'` | `inline` rests as plain text and reveals the editor on click; `form` is always an open, editable field. |
43
+ | `editControl` | `boolean` | `true` | Show the floating confirm / cancel control while active. |
44
+ | `icon` | `boolean` | `true` | Show the edit affordance icon in the inline display state. |
45
+ | `editIcon` | `ReactNode` | `<Edit />` | Override the default edit (pencil) icon. |
46
+ | `tools` | `ReactNode` | — | Formatting toolbar (e.g. `IconButton`s) shown in a floating bar below the field while active. |
47
+ | `rows` | `number` | `1` | Minimum number of visible text rows while editing. |
48
+ | `textStyle` | `'h1'…'h5' \| 'display' \| 'body-lg'…'body-xxs'` | — | Named typography style; overrides the default font. |
49
+ | `richText` | `boolean` | `false` | Enable rich-text editing (web only); the value becomes HTML. Wire a toolbar via `tools` + `document.execCommand`. Falls back to a plain field on native. |
50
+ | `disabled` | `boolean` | `false` | Disable the control. |
51
+ | `error` | `boolean` | `false` | Apply error styling. |
52
+ | `errorMessage` | `string` | — | Error message; also marks the field invalid. |
53
+ | `id` | `string` | `auto` | HTML id for the field. |
54
+ | `aria-label` | `string` | — | Accessible label when no visible label is present. |
55
+ | `aria-labelledby` | `string` | — | ID of an external element that labels the field. |
56
+ | `testID` | `string` | — | Test identifier. |
57
+
58
+ `InputEdit` also accepts the standard `TextareaHTMLAttributes`, except `size`, `value`, and `defaultValue` (redefined above) and `onChange` (use `onChangeText`).
59
+
60
+ Inherits `ThemeOverrideProps` (`themeMode`, `themeProductContext`).
61
+
62
+ ## Examples
63
+
64
+ ### Inline editing
65
+
66
+ ```tsx
67
+ const [value, setValue] = useState('Input text');
68
+
69
+ <InputEdit value={value} onChangeText={setValue} onConfirm={(v) => save(v)} />;
70
+ ```
71
+
72
+ ### Form mode
73
+
74
+ ```tsx
75
+ <InputEdit
76
+ mode="form"
77
+ placeholder="Add a description…"
78
+ onConfirm={(v) => save(v)}
79
+ />
80
+ ```
81
+
82
+ ### Text styles
83
+
84
+ ```tsx
85
+ <InputEdit textStyle="h1" defaultValue="Editable heading" />
86
+ <InputEdit textStyle="body-lg" defaultValue="Body text" />
87
+ ```
88
+
89
+ ### Formatting tools
90
+
91
+ ```tsx
92
+ import { IconButton } from '@xsolla/xui-button';
93
+ import { BoldText, ItalicText, Link } from '@xsolla/xui-icons-base';
94
+
95
+ <InputEdit
96
+ defaultValue="Input text"
97
+ tools={
98
+ <>
99
+ <IconButton variant="tertiary" tone="mono" size="xs" icon={<BoldText />} aria-label="Bold" />
100
+ <IconButton variant="tertiary" tone="mono" size="xs" icon={<ItalicText />} aria-label="Italic" />
101
+ <IconButton variant="tertiary" tone="mono" size="xs" icon={<Link />} aria-label="Add link" />
102
+ </>
103
+ }
104
+ />;
105
+ ```
106
+
107
+ ### Rich text
108
+
109
+ Set `richText` to make the field a `contenteditable` surface whose value is HTML. The toolbar runs `document.execCommand` on the focused selection — vary it per product (alignment, bold/italic/underline, link, …). Web only; falls back to a plain field on native. The HTML is not sanitized — sanitize before rendering untrusted content.
110
+
111
+ ```tsx
112
+ import { IconButton } from '@xsolla/xui-button';
113
+ import {
114
+ TextAlignLeft, TextAlignCenter, TextAlignRight,
115
+ BoldText, ItalicText, UnderlineText, Link,
116
+ } from '@xsolla/xui-icons-base';
117
+
118
+ const [value, setValue] = useState('<b>Bold</b> text');
119
+ const exec = (command, arg) => () => document.execCommand(command, false, arg);
120
+
121
+ const formats = [
122
+ { icon: <TextAlignLeft />, label: 'Align left', run: exec('justifyLeft') },
123
+ { icon: <TextAlignCenter />, label: 'Align center', run: exec('justifyCenter') },
124
+ { icon: <TextAlignRight />, label: 'Align right', run: exec('justifyRight') },
125
+ { icon: <BoldText />, label: 'Bold', run: exec('bold') },
126
+ { icon: <ItalicText />, label: 'Italic', run: exec('italic') },
127
+ { icon: <UnderlineText />, label: 'Underline', run: exec('underline') },
128
+ { icon: <Link />, label: 'Add link', run: () => {
129
+ const url = window.prompt('Link URL');
130
+ if (url) document.execCommand('createLink', false, url);
131
+ } },
132
+ ];
133
+
134
+ <InputEdit
135
+ richText
136
+ value={value}
137
+ onChangeText={setValue}
138
+ tools={formats.map((f) => (
139
+ <IconButton key={f.label} variant="tertiary" tone="mono" size="xs"
140
+ icon={f.icon} aria-label={f.label} onPress={f.run} />
141
+ ))}
142
+ />;
143
+ ```
144
+
145
+ ### Error state
146
+
147
+ ```tsx
148
+ const [value, setValue] = useState('Input text');
149
+
150
+ <InputEdit
151
+ value={value}
152
+ onChangeText={setValue}
153
+ errorMessage="This field is required"
154
+ />;
155
+ ```
156
+
157
+ ## Accessibility
158
+
159
+ - Renders a `<textarea>` (or a `contenteditable` `role="textbox"` when `richText` is set); provide a label via `aria-label` or `aria-labelledby` (there is no visible label slot).
160
+ - Error messages are linked through `aria-describedby` and sit in a polite live region (`aria-live="polite"`).
161
+ - `aria-invalid` and `aria-disabled` reflect error and disabled state.
162
+ - The decorative edit icon is `aria-hidden`; the confirm / cancel buttons expose `aria-label`s.
163
+ - Keyboard: `Tab` to focus, `Escape` cancels, `Cmd`/`Ctrl` + `Enter` commits, `Enter` inserts a new line.
164
+ - Rich-text mode is web only and the stored HTML is not sanitized — sanitize before rendering untrusted values.
@@ -0,0 +1,117 @@
1
+ import React, { TextareaHTMLAttributes, ReactNode } from 'react';
2
+ import { ThemeOverrideProps } from '@xsolla/xui-core';
3
+
4
+ type InputEditMode = "inline" | "form";
5
+ /**
6
+ * Named typography styles, resolved from the theme's typography tokens. Drives the
7
+ * field's font family / size / weight / line-height so the text can match surrounding
8
+ * content (e.g. a heading) rather than only the fixed body sizes.
9
+ */
10
+ type InputEditTextStyle = "h1" | "h2" | "h3" | "h4" | "h5" | "display" | "body-lg" | "body-md" | "body-sm" | "body-xs" | "body-xxs";
11
+ interface InputEditProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, "size" | "onChange" | "value" | "defaultValue">, ThemeOverrideProps {
12
+ /**
13
+ * Controlled value of the field.
14
+ */
15
+ value?: string;
16
+ /**
17
+ * Initial value for uncontrolled usage.
18
+ */
19
+ defaultValue?: string;
20
+ /**
21
+ * Placeholder shown when the field is empty.
22
+ */
23
+ placeholder?: string;
24
+ /**
25
+ * Change handler receiving the current text (HTML when `richText` is set).
26
+ */
27
+ onChangeText?: (text: string) => void;
28
+ /**
29
+ * Called when the edit is confirmed (check button or `Cmd`/`Ctrl` + `Enter`).
30
+ */
31
+ onConfirm?: (value: string) => void;
32
+ /**
33
+ * Called when the edit is cancelled (cross button or `Escape`). The value is reverted.
34
+ */
35
+ onCancel?: () => void;
36
+ /**
37
+ * Minimum number of visible text rows while editing.
38
+ */
39
+ rows?: number;
40
+ /**
41
+ * Show the floating confirm / cancel control while editing.
42
+ */
43
+ editControl?: boolean;
44
+ /**
45
+ * Show the edit affordance icon in display mode.
46
+ */
47
+ icon?: boolean;
48
+ /**
49
+ * Override the default edit (pencil) icon.
50
+ */
51
+ editIcon?: ReactNode;
52
+ /**
53
+ * Optional formatting toolbar shown in a floating bar below the field while editing
54
+ * (e.g. text-align / bold / link `IconButton`s). Rendered to the left, mirroring the
55
+ * confirm / cancel control on the right.
56
+ */
57
+ tools?: ReactNode;
58
+ /**
59
+ * Activation mode. `"inline"` (default) rests as plain text and reveals the editor on
60
+ * click; `"form"` is always an open, editable field (like a standard form text area).
61
+ */
62
+ mode?: InputEditMode;
63
+ /**
64
+ * Named typography style applied to the text and editor (e.g. `"h1"`, `"body-lg"`).
65
+ * Overrides the default font.
66
+ */
67
+ textStyle?: InputEditTextStyle;
68
+ /**
69
+ * Enable rich-text editing (web only). The field becomes a `contenteditable` surface
70
+ * and `value` / `onChangeText` / `onConfirm` carry HTML. Wire a toolbar via `tools`
71
+ * using `document.execCommand`. Falls back to a plain text field on React Native.
72
+ * The HTML is not sanitized — sanitize before rendering untrusted values.
73
+ */
74
+ richText?: boolean;
75
+ /**
76
+ * Disable the control.
77
+ */
78
+ disabled?: boolean;
79
+ /**
80
+ * Highlight the control as invalid.
81
+ */
82
+ error?: boolean;
83
+ /**
84
+ * Error message displayed below the field (implies `error`).
85
+ */
86
+ errorMessage?: string;
87
+ /**
88
+ * Unique identifier for the input element. Used for accessibility linking.
89
+ */
90
+ id?: string;
91
+ /**
92
+ * Accessible label for screen readers (use when no visible label is present).
93
+ */
94
+ "aria-label"?: string;
95
+ /**
96
+ * ID of an external element that labels the field (e.g. a heading placed above it).
97
+ */
98
+ "aria-labelledby"?: string;
99
+ /**
100
+ * Test identifier.
101
+ */
102
+ testID?: string;
103
+ /**
104
+ * Optional class name applied to the root element (web).
105
+ */
106
+ className?: string;
107
+ }
108
+ /**
109
+ * A multi-line text field for editing freeform text. In `"inline"` mode it rests as
110
+ * plain text and reveals a highlighted editor on click; in `"form"` mode it is always
111
+ * an open, editable field. `Enter` inserts a new line; confirm via the floating control
112
+ * or `Cmd`/`Ctrl` + `Enter`; clicking outside also commits. `Escape` cancels and
113
+ * reverts.
114
+ */
115
+ declare const InputEdit: React.ForwardRefExoticComponent<InputEditProps & React.RefAttributes<HTMLTextAreaElement | HTMLDivElement>>;
116
+
117
+ export { InputEdit, type InputEditProps };
@@ -0,0 +1,117 @@
1
+ import React, { TextareaHTMLAttributes, ReactNode } from 'react';
2
+ import { ThemeOverrideProps } from '@xsolla/xui-core';
3
+
4
+ type InputEditMode = "inline" | "form";
5
+ /**
6
+ * Named typography styles, resolved from the theme's typography tokens. Drives the
7
+ * field's font family / size / weight / line-height so the text can match surrounding
8
+ * content (e.g. a heading) rather than only the fixed body sizes.
9
+ */
10
+ type InputEditTextStyle = "h1" | "h2" | "h3" | "h4" | "h5" | "display" | "body-lg" | "body-md" | "body-sm" | "body-xs" | "body-xxs";
11
+ interface InputEditProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, "size" | "onChange" | "value" | "defaultValue">, ThemeOverrideProps {
12
+ /**
13
+ * Controlled value of the field.
14
+ */
15
+ value?: string;
16
+ /**
17
+ * Initial value for uncontrolled usage.
18
+ */
19
+ defaultValue?: string;
20
+ /**
21
+ * Placeholder shown when the field is empty.
22
+ */
23
+ placeholder?: string;
24
+ /**
25
+ * Change handler receiving the current text (HTML when `richText` is set).
26
+ */
27
+ onChangeText?: (text: string) => void;
28
+ /**
29
+ * Called when the edit is confirmed (check button or `Cmd`/`Ctrl` + `Enter`).
30
+ */
31
+ onConfirm?: (value: string) => void;
32
+ /**
33
+ * Called when the edit is cancelled (cross button or `Escape`). The value is reverted.
34
+ */
35
+ onCancel?: () => void;
36
+ /**
37
+ * Minimum number of visible text rows while editing.
38
+ */
39
+ rows?: number;
40
+ /**
41
+ * Show the floating confirm / cancel control while editing.
42
+ */
43
+ editControl?: boolean;
44
+ /**
45
+ * Show the edit affordance icon in display mode.
46
+ */
47
+ icon?: boolean;
48
+ /**
49
+ * Override the default edit (pencil) icon.
50
+ */
51
+ editIcon?: ReactNode;
52
+ /**
53
+ * Optional formatting toolbar shown in a floating bar below the field while editing
54
+ * (e.g. text-align / bold / link `IconButton`s). Rendered to the left, mirroring the
55
+ * confirm / cancel control on the right.
56
+ */
57
+ tools?: ReactNode;
58
+ /**
59
+ * Activation mode. `"inline"` (default) rests as plain text and reveals the editor on
60
+ * click; `"form"` is always an open, editable field (like a standard form text area).
61
+ */
62
+ mode?: InputEditMode;
63
+ /**
64
+ * Named typography style applied to the text and editor (e.g. `"h1"`, `"body-lg"`).
65
+ * Overrides the default font.
66
+ */
67
+ textStyle?: InputEditTextStyle;
68
+ /**
69
+ * Enable rich-text editing (web only). The field becomes a `contenteditable` surface
70
+ * and `value` / `onChangeText` / `onConfirm` carry HTML. Wire a toolbar via `tools`
71
+ * using `document.execCommand`. Falls back to a plain text field on React Native.
72
+ * The HTML is not sanitized — sanitize before rendering untrusted values.
73
+ */
74
+ richText?: boolean;
75
+ /**
76
+ * Disable the control.
77
+ */
78
+ disabled?: boolean;
79
+ /**
80
+ * Highlight the control as invalid.
81
+ */
82
+ error?: boolean;
83
+ /**
84
+ * Error message displayed below the field (implies `error`).
85
+ */
86
+ errorMessage?: string;
87
+ /**
88
+ * Unique identifier for the input element. Used for accessibility linking.
89
+ */
90
+ id?: string;
91
+ /**
92
+ * Accessible label for screen readers (use when no visible label is present).
93
+ */
94
+ "aria-label"?: string;
95
+ /**
96
+ * ID of an external element that labels the field (e.g. a heading placed above it).
97
+ */
98
+ "aria-labelledby"?: string;
99
+ /**
100
+ * Test identifier.
101
+ */
102
+ testID?: string;
103
+ /**
104
+ * Optional class name applied to the root element (web).
105
+ */
106
+ className?: string;
107
+ }
108
+ /**
109
+ * A multi-line text field for editing freeform text. In `"inline"` mode it rests as
110
+ * plain text and reveals a highlighted editor on click; in `"form"` mode it is always
111
+ * an open, editable field. `Enter` inserts a new line; confirm via the floating control
112
+ * or `Cmd`/`Ctrl` + `Enter`; clicking outside also commits. `Escape` cancels and
113
+ * reverts.
114
+ */
115
+ declare const InputEdit: React.ForwardRefExoticComponent<InputEditProps & React.RefAttributes<HTMLTextAreaElement | HTMLDivElement>>;
116
+
117
+ export { InputEdit, type InputEditProps };