@dealdeploy/skl 0.1.6 → 0.1.8
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/.agents/skills/opentui/SKILL.md +198 -0
- package/.agents/skills/opentui/references/animation/REFERENCE.md +431 -0
- package/.agents/skills/opentui/references/components/REFERENCE.md +143 -0
- package/.agents/skills/opentui/references/components/code-diff.md +496 -0
- package/.agents/skills/opentui/references/components/containers.md +412 -0
- package/.agents/skills/opentui/references/components/inputs.md +531 -0
- package/.agents/skills/opentui/references/components/text-display.md +384 -0
- package/.agents/skills/opentui/references/core/REFERENCE.md +145 -0
- package/.agents/skills/opentui/references/core/api.md +506 -0
- package/.agents/skills/opentui/references/core/configuration.md +166 -0
- package/.agents/skills/opentui/references/core/gotchas.md +393 -0
- package/.agents/skills/opentui/references/core/patterns.md +448 -0
- package/.agents/skills/opentui/references/keyboard/REFERENCE.md +511 -0
- package/.agents/skills/opentui/references/layout/REFERENCE.md +337 -0
- package/.agents/skills/opentui/references/layout/patterns.md +444 -0
- package/.agents/skills/opentui/references/react/REFERENCE.md +174 -0
- package/.agents/skills/opentui/references/react/api.md +435 -0
- package/.agents/skills/opentui/references/react/configuration.md +301 -0
- package/.agents/skills/opentui/references/react/gotchas.md +443 -0
- package/.agents/skills/opentui/references/react/patterns.md +501 -0
- package/.agents/skills/opentui/references/solid/REFERENCE.md +201 -0
- package/.agents/skills/opentui/references/solid/api.md +543 -0
- package/.agents/skills/opentui/references/solid/configuration.md +315 -0
- package/.agents/skills/opentui/references/solid/gotchas.md +415 -0
- package/.agents/skills/opentui/references/solid/patterns.md +558 -0
- package/.agents/skills/opentui/references/testing/REFERENCE.md +614 -0
- package/.claude/settings.local.json +11 -0
- package/.claude/skills/opentui/SKILL.md +198 -0
- package/.claude/skills/opentui/references/animation/REFERENCE.md +431 -0
- package/.claude/skills/opentui/references/components/REFERENCE.md +143 -0
- package/.claude/skills/opentui/references/components/code-diff.md +496 -0
- package/.claude/skills/opentui/references/components/containers.md +412 -0
- package/.claude/skills/opentui/references/components/inputs.md +531 -0
- package/.claude/skills/opentui/references/components/text-display.md +384 -0
- package/.claude/skills/opentui/references/core/REFERENCE.md +145 -0
- package/.claude/skills/opentui/references/core/api.md +506 -0
- package/.claude/skills/opentui/references/core/configuration.md +166 -0
- package/.claude/skills/opentui/references/core/gotchas.md +393 -0
- package/.claude/skills/opentui/references/core/patterns.md +448 -0
- package/.claude/skills/opentui/references/keyboard/REFERENCE.md +511 -0
- package/.claude/skills/opentui/references/layout/REFERENCE.md +337 -0
- package/.claude/skills/opentui/references/layout/patterns.md +444 -0
- package/.claude/skills/opentui/references/react/REFERENCE.md +174 -0
- package/.claude/skills/opentui/references/react/api.md +435 -0
- package/.claude/skills/opentui/references/react/configuration.md +301 -0
- package/.claude/skills/opentui/references/react/gotchas.md +443 -0
- package/.claude/skills/opentui/references/react/patterns.md +501 -0
- package/.claude/skills/opentui/references/solid/REFERENCE.md +201 -0
- package/.claude/skills/opentui/references/solid/api.md +543 -0
- package/.claude/skills/opentui/references/solid/configuration.md +315 -0
- package/.claude/skills/opentui/references/solid/gotchas.md +415 -0
- package/.claude/skills/opentui/references/solid/patterns.md +558 -0
- package/.claude/skills/opentui/references/testing/REFERENCE.md +614 -0
- package/index.ts +429 -86
- package/package.json +2 -1
- package/update.ts +87 -0
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
# Input Components
|
|
2
|
+
|
|
3
|
+
Components for user input in OpenTUI.
|
|
4
|
+
|
|
5
|
+
## Input Component
|
|
6
|
+
|
|
7
|
+
Single-line text input field.
|
|
8
|
+
|
|
9
|
+
### Basic Usage
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
// React
|
|
13
|
+
<input
|
|
14
|
+
value={value}
|
|
15
|
+
onChange={(newValue) => setValue(newValue)}
|
|
16
|
+
placeholder="Enter text..."
|
|
17
|
+
focused
|
|
18
|
+
/>
|
|
19
|
+
|
|
20
|
+
// Solid
|
|
21
|
+
<input
|
|
22
|
+
value={value()}
|
|
23
|
+
onInput={(newValue) => setValue(newValue)}
|
|
24
|
+
placeholder="Enter text..."
|
|
25
|
+
focused
|
|
26
|
+
/>
|
|
27
|
+
|
|
28
|
+
// Core
|
|
29
|
+
const input = new InputRenderable(renderer, {
|
|
30
|
+
id: "name",
|
|
31
|
+
placeholder: "Enter text...",
|
|
32
|
+
})
|
|
33
|
+
input.on(InputRenderableEvents.CHANGE, (value) => {
|
|
34
|
+
console.log("Value:", value)
|
|
35
|
+
})
|
|
36
|
+
input.focus()
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Styling
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
<input
|
|
43
|
+
width={30}
|
|
44
|
+
backgroundColor="#1a1a1a"
|
|
45
|
+
textColor="#FFFFFF"
|
|
46
|
+
cursorColor="#00FF00"
|
|
47
|
+
focusedBackgroundColor="#2a2a2a"
|
|
48
|
+
placeholderColor="#666666"
|
|
49
|
+
/>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Events
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
// React
|
|
56
|
+
<input
|
|
57
|
+
onChange={(value) => console.log("Changed:", value)}
|
|
58
|
+
onFocus={() => console.log("Focused")}
|
|
59
|
+
onBlur={() => console.log("Blurred")}
|
|
60
|
+
/>
|
|
61
|
+
|
|
62
|
+
// Core
|
|
63
|
+
input.on(InputRenderableEvents.CHANGE, (value) => {})
|
|
64
|
+
input.on(InputRenderableEvents.FOCUS, () => {})
|
|
65
|
+
input.on(InputRenderableEvents.BLUR, () => {})
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Controlled Input
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
// React
|
|
72
|
+
function ControlledInput() {
|
|
73
|
+
const [value, setValue] = useState("")
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<input
|
|
77
|
+
value={value}
|
|
78
|
+
onChange={setValue}
|
|
79
|
+
focused
|
|
80
|
+
/>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Solid
|
|
85
|
+
function ControlledInput() {
|
|
86
|
+
const [value, setValue] = createSignal("")
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<input
|
|
90
|
+
value={value()}
|
|
91
|
+
onInput={setValue}
|
|
92
|
+
focused
|
|
93
|
+
/>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Textarea Component
|
|
99
|
+
|
|
100
|
+
Multi-line text input field.
|
|
101
|
+
|
|
102
|
+
### Basic Usage
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
// React
|
|
106
|
+
<textarea
|
|
107
|
+
value={text}
|
|
108
|
+
onChange={(newText) => setText(newText)}
|
|
109
|
+
placeholder="Enter multiple lines..."
|
|
110
|
+
width={40}
|
|
111
|
+
height={10}
|
|
112
|
+
focused
|
|
113
|
+
/>
|
|
114
|
+
|
|
115
|
+
// Solid
|
|
116
|
+
<textarea
|
|
117
|
+
value={text()}
|
|
118
|
+
onInput={(newText) => setText(newText)}
|
|
119
|
+
placeholder="Enter multiple lines..."
|
|
120
|
+
width={40}
|
|
121
|
+
height={10}
|
|
122
|
+
focused
|
|
123
|
+
/>
|
|
124
|
+
|
|
125
|
+
// Core
|
|
126
|
+
const textarea = new TextareaRenderable(renderer, {
|
|
127
|
+
id: "editor",
|
|
128
|
+
width: 40,
|
|
129
|
+
height: 10,
|
|
130
|
+
placeholder: "Enter text...",
|
|
131
|
+
})
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Features
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
<textarea
|
|
138
|
+
showLineNumbers // Display line numbers
|
|
139
|
+
wrapText // Wrap long lines
|
|
140
|
+
readOnly // Disable editing
|
|
141
|
+
tabSize={2} // Tab character width
|
|
142
|
+
/>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Syntax Highlighting
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
<textarea
|
|
149
|
+
language="typescript"
|
|
150
|
+
value={code}
|
|
151
|
+
onChange={setCode}
|
|
152
|
+
/>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Select Component
|
|
156
|
+
|
|
157
|
+
List selection for choosing from options.
|
|
158
|
+
|
|
159
|
+
### Basic Usage
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
// React
|
|
163
|
+
<select
|
|
164
|
+
options={[
|
|
165
|
+
{ name: "Option 1", description: "First option", value: "1" },
|
|
166
|
+
{ name: "Option 2", description: "Second option", value: "2" },
|
|
167
|
+
{ name: "Option 3", description: "Third option", value: "3" },
|
|
168
|
+
]}
|
|
169
|
+
onSelect={(index, option) => {
|
|
170
|
+
console.log("Selected:", option.name) // Called when Enter is pressed
|
|
171
|
+
}}
|
|
172
|
+
focused
|
|
173
|
+
/>
|
|
174
|
+
|
|
175
|
+
// Solid
|
|
176
|
+
<select
|
|
177
|
+
options={[
|
|
178
|
+
{ name: "Option 1", description: "First option", value: "1" },
|
|
179
|
+
{ name: "Option 2", description: "Second option", value: "2" },
|
|
180
|
+
]}
|
|
181
|
+
onSelect={(index, option) => {
|
|
182
|
+
console.log("Selected:", option.name) // Called when Enter is pressed
|
|
183
|
+
}}
|
|
184
|
+
focused
|
|
185
|
+
/>
|
|
186
|
+
|
|
187
|
+
// Core
|
|
188
|
+
const select = new SelectRenderable(renderer, {
|
|
189
|
+
id: "menu",
|
|
190
|
+
options: [
|
|
191
|
+
{ name: "Option 1", description: "First option", value: "1" },
|
|
192
|
+
{ name: "Option 2", description: "Second option", value: "2" },
|
|
193
|
+
],
|
|
194
|
+
})
|
|
195
|
+
select.on(SelectRenderableEvents.ITEM_SELECTED, (index, option) => {
|
|
196
|
+
console.log("Selected:", option.name) // Called when Enter is pressed
|
|
197
|
+
})
|
|
198
|
+
select.focus()
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Option Format
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
interface SelectOption {
|
|
205
|
+
name: string // Display text
|
|
206
|
+
description?: string // Optional description shown below
|
|
207
|
+
value?: any // Associated value
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Styling
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
<select
|
|
215
|
+
height={8} // Visible height
|
|
216
|
+
selectedIndex={0} // Initially selected
|
|
217
|
+
showScrollIndicator // Show scroll arrows
|
|
218
|
+
selectedBackgroundColor="#333"
|
|
219
|
+
selectedTextColor="#fff"
|
|
220
|
+
highlightBackgroundColor="#444"
|
|
221
|
+
/>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Navigation
|
|
225
|
+
|
|
226
|
+
Default keybindings:
|
|
227
|
+
- `Up` / `k` - Move up
|
|
228
|
+
- `Down` / `j` - Move down
|
|
229
|
+
- `Enter` - Select item
|
|
230
|
+
|
|
231
|
+
### Events
|
|
232
|
+
|
|
233
|
+
**Important**: `onSelect` and `onChange` serve different purposes:
|
|
234
|
+
|
|
235
|
+
| Event | Trigger | Use Case |
|
|
236
|
+
|-------|---------|----------|
|
|
237
|
+
| `onSelect` | **Enter key pressed** - user confirms selection | Perform action with selected item |
|
|
238
|
+
| `onChange` | **Arrow keys** - user navigates list | Preview, update UI as user browses |
|
|
239
|
+
|
|
240
|
+
```tsx
|
|
241
|
+
// React/Solid
|
|
242
|
+
<select
|
|
243
|
+
onSelect={(index, option) => {
|
|
244
|
+
// Called when Enter is pressed - selection confirmed
|
|
245
|
+
console.log("User selected:", option.name)
|
|
246
|
+
performAction(option)
|
|
247
|
+
}}
|
|
248
|
+
onChange={(index, option) => {
|
|
249
|
+
// Called when navigating with arrow keys
|
|
250
|
+
console.log("Browsing:", option.name)
|
|
251
|
+
showPreview(option)
|
|
252
|
+
}}
|
|
253
|
+
/>
|
|
254
|
+
|
|
255
|
+
// Core
|
|
256
|
+
select.on(SelectRenderableEvents.ITEM_SELECTED, (index, option) => {
|
|
257
|
+
// Called when Enter is pressed
|
|
258
|
+
})
|
|
259
|
+
select.on(SelectRenderableEvents.SELECTION_CHANGED, (index, option) => {
|
|
260
|
+
// Called when navigating with arrow keys
|
|
261
|
+
})
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Tab Select Component
|
|
265
|
+
|
|
266
|
+
Horizontal tab-based selection.
|
|
267
|
+
|
|
268
|
+
### Basic Usage
|
|
269
|
+
|
|
270
|
+
```tsx
|
|
271
|
+
// React
|
|
272
|
+
<tab-select
|
|
273
|
+
options={[
|
|
274
|
+
{ name: "Home", description: "Dashboard view" },
|
|
275
|
+
{ name: "Settings", description: "Configuration" },
|
|
276
|
+
{ name: "Help", description: "Documentation" },
|
|
277
|
+
]}
|
|
278
|
+
onSelect={(index, option) => {
|
|
279
|
+
console.log("Tab selected:", option.name) // Called when Enter is pressed
|
|
280
|
+
}}
|
|
281
|
+
focused
|
|
282
|
+
/>
|
|
283
|
+
|
|
284
|
+
// Solid (note underscore)
|
|
285
|
+
<tab_select
|
|
286
|
+
options={[
|
|
287
|
+
{ name: "Home", description: "Dashboard view" },
|
|
288
|
+
{ name: "Settings", description: "Configuration" },
|
|
289
|
+
]}
|
|
290
|
+
onSelect={(index, option) => {
|
|
291
|
+
console.log("Tab selected:", option.name) // Called when Enter is pressed
|
|
292
|
+
}}
|
|
293
|
+
focused
|
|
294
|
+
/>
|
|
295
|
+
|
|
296
|
+
// Core
|
|
297
|
+
const tabs = new TabSelectRenderable(renderer, {
|
|
298
|
+
id: "tabs",
|
|
299
|
+
options: [...],
|
|
300
|
+
tabWidth: 20,
|
|
301
|
+
})
|
|
302
|
+
tabs.on(TabSelectRenderableEvents.ITEM_SELECTED, (index, option) => {
|
|
303
|
+
console.log("Tab selected:", option.name) // Called when Enter is pressed
|
|
304
|
+
})
|
|
305
|
+
tabs.focus()
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Events
|
|
309
|
+
|
|
310
|
+
Same pattern as Select - `onSelect` for Enter key, `onChange` for navigation:
|
|
311
|
+
|
|
312
|
+
```tsx
|
|
313
|
+
<tab-select
|
|
314
|
+
onSelect={(index, option) => {
|
|
315
|
+
// Called when Enter is pressed - switch to tab
|
|
316
|
+
setActiveTab(index)
|
|
317
|
+
}}
|
|
318
|
+
onChange={(index, option) => {
|
|
319
|
+
// Called when navigating with arrow keys
|
|
320
|
+
showTabPreview(option)
|
|
321
|
+
}}
|
|
322
|
+
/>
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Styling
|
|
326
|
+
|
|
327
|
+
```tsx
|
|
328
|
+
// React
|
|
329
|
+
<tab-select
|
|
330
|
+
tabWidth={20} // Width of each tab
|
|
331
|
+
selectedIndex={0} // Initially selected tab
|
|
332
|
+
/>
|
|
333
|
+
|
|
334
|
+
// Solid
|
|
335
|
+
<tab_select
|
|
336
|
+
tabWidth={20}
|
|
337
|
+
selectedIndex={0}
|
|
338
|
+
/>
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Navigation
|
|
342
|
+
|
|
343
|
+
Default keybindings:
|
|
344
|
+
- `Left` / `[` - Previous tab
|
|
345
|
+
- `Right` / `]` - Next tab
|
|
346
|
+
- `Enter` - Select tab
|
|
347
|
+
|
|
348
|
+
## Focus Management
|
|
349
|
+
|
|
350
|
+
### Single Focused Input
|
|
351
|
+
|
|
352
|
+
```tsx
|
|
353
|
+
function SingleInput() {
|
|
354
|
+
return <input placeholder="I'm focused" focused />
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Multiple Inputs with Focus State
|
|
359
|
+
|
|
360
|
+
```tsx
|
|
361
|
+
// React
|
|
362
|
+
function Form() {
|
|
363
|
+
const [focusIndex, setFocusIndex] = useState(0)
|
|
364
|
+
const fields = ["name", "email", "message"]
|
|
365
|
+
|
|
366
|
+
useKeyboard((key) => {
|
|
367
|
+
if (key.name === "tab") {
|
|
368
|
+
setFocusIndex(i => (i + 1) % fields.length)
|
|
369
|
+
}
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
return (
|
|
373
|
+
<box flexDirection="column" gap={1}>
|
|
374
|
+
{fields.map((field, i) => (
|
|
375
|
+
<input
|
|
376
|
+
key={field}
|
|
377
|
+
placeholder={`Enter ${field}`}
|
|
378
|
+
focused={i === focusIndex}
|
|
379
|
+
/>
|
|
380
|
+
))}
|
|
381
|
+
</box>
|
|
382
|
+
)
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### Focus Methods (Core)
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
input.focus() // Give focus
|
|
390
|
+
input.blur() // Remove focus
|
|
391
|
+
input.isFocused() // Check focus state
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## Form Patterns
|
|
395
|
+
|
|
396
|
+
### Login Form
|
|
397
|
+
|
|
398
|
+
```tsx
|
|
399
|
+
function LoginForm() {
|
|
400
|
+
const [username, setUsername] = useState("")
|
|
401
|
+
const [password, setPassword] = useState("")
|
|
402
|
+
const [focusField, setFocusField] = useState<"username" | "password">("username")
|
|
403
|
+
|
|
404
|
+
useKeyboard((key) => {
|
|
405
|
+
if (key.name === "tab") {
|
|
406
|
+
setFocusField(f => f === "username" ? "password" : "username")
|
|
407
|
+
}
|
|
408
|
+
if (key.name === "enter") {
|
|
409
|
+
handleLogin()
|
|
410
|
+
}
|
|
411
|
+
})
|
|
412
|
+
|
|
413
|
+
return (
|
|
414
|
+
<box flexDirection="column" gap={1} border padding={2}>
|
|
415
|
+
<box flexDirection="row" gap={1}>
|
|
416
|
+
<text>Username:</text>
|
|
417
|
+
<input
|
|
418
|
+
value={username}
|
|
419
|
+
onChange={setUsername}
|
|
420
|
+
focused={focusField === "username"}
|
|
421
|
+
width={20}
|
|
422
|
+
/>
|
|
423
|
+
</box>
|
|
424
|
+
<box flexDirection="row" gap={1}>
|
|
425
|
+
<text>Password:</text>
|
|
426
|
+
<input
|
|
427
|
+
value={password}
|
|
428
|
+
onChange={setPassword}
|
|
429
|
+
focused={focusField === "password"}
|
|
430
|
+
width={20}
|
|
431
|
+
/>
|
|
432
|
+
</box>
|
|
433
|
+
</box>
|
|
434
|
+
)
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Search with Results
|
|
439
|
+
|
|
440
|
+
```tsx
|
|
441
|
+
function SearchableList({ items, onItemSelected }) {
|
|
442
|
+
const [query, setQuery] = useState("")
|
|
443
|
+
const [focusSearch, setFocusSearch] = useState(true)
|
|
444
|
+
const [preview, setPreview] = useState(null)
|
|
445
|
+
|
|
446
|
+
const filtered = items.filter(item =>
|
|
447
|
+
item.toLowerCase().includes(query.toLowerCase())
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
useKeyboard((key) => {
|
|
451
|
+
if (key.name === "tab") {
|
|
452
|
+
setFocusSearch(f => !f)
|
|
453
|
+
}
|
|
454
|
+
})
|
|
455
|
+
|
|
456
|
+
return (
|
|
457
|
+
<box flexDirection="column">
|
|
458
|
+
<input
|
|
459
|
+
value={query}
|
|
460
|
+
onChange={setQuery}
|
|
461
|
+
placeholder="Search..."
|
|
462
|
+
focused={focusSearch}
|
|
463
|
+
/>
|
|
464
|
+
<select
|
|
465
|
+
options={filtered.map(item => ({ name: item }))}
|
|
466
|
+
focused={!focusSearch}
|
|
467
|
+
height={10}
|
|
468
|
+
onSelect={(index, option) => {
|
|
469
|
+
// Enter pressed - confirm selection
|
|
470
|
+
onItemSelected(option)
|
|
471
|
+
}}
|
|
472
|
+
onChange={(index, option) => {
|
|
473
|
+
// Navigating - show preview
|
|
474
|
+
setPreview(option)
|
|
475
|
+
}}
|
|
476
|
+
/>
|
|
477
|
+
</box>
|
|
478
|
+
)
|
|
479
|
+
}
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
## Gotchas
|
|
483
|
+
|
|
484
|
+
### Focus Required
|
|
485
|
+
|
|
486
|
+
Inputs must be focused to receive keyboard input:
|
|
487
|
+
|
|
488
|
+
```tsx
|
|
489
|
+
// WRONG - won't receive input
|
|
490
|
+
<input placeholder="Type here" />
|
|
491
|
+
|
|
492
|
+
// CORRECT
|
|
493
|
+
<input placeholder="Type here" focused />
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
### Select Options Format
|
|
497
|
+
|
|
498
|
+
Options must be objects with `name` property:
|
|
499
|
+
|
|
500
|
+
```tsx
|
|
501
|
+
// WRONG
|
|
502
|
+
<select options={["a", "b", "c"]} />
|
|
503
|
+
|
|
504
|
+
// CORRECT
|
|
505
|
+
<select options={[
|
|
506
|
+
{ name: "A", description: "Option A" },
|
|
507
|
+
{ name: "B", description: "Option B" },
|
|
508
|
+
]} />
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
### Solid Uses Underscores
|
|
512
|
+
|
|
513
|
+
```tsx
|
|
514
|
+
// React
|
|
515
|
+
<tab-select />
|
|
516
|
+
|
|
517
|
+
// Solid
|
|
518
|
+
<tab_select />
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### Value vs onInput (Solid)
|
|
522
|
+
|
|
523
|
+
Solid uses `onInput` instead of `onChange`:
|
|
524
|
+
|
|
525
|
+
```tsx
|
|
526
|
+
// React
|
|
527
|
+
<input value={value} onChange={setValue} />
|
|
528
|
+
|
|
529
|
+
// Solid
|
|
530
|
+
<input value={value()} onInput={setValue} />
|
|
531
|
+
```
|