@lingxia/skill 0.8.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 +95 -0
- package/bin/install.mjs +247 -0
- package/package.json +49 -0
- package/scripts/sync.mjs +69 -0
- package/skill/SKILL.md +334 -0
- package/skill/app/apple-sdk.md +312 -0
- package/skill/app/applinks.md +289 -0
- package/skill/app/project.md +760 -0
- package/skill/cli/lxdev.md +195 -0
- package/skill/cli/reference.md +481 -0
- package/skill/examples/hello-host-js/README.md +25 -0
- package/skill/examples/hello-host-js/home/lxapp.json +12 -0
- package/skill/examples/hello-host-js/home/pages/home/index.json +4 -0
- package/skill/examples/hello-host-js/home/pages/home/index.ts +14 -0
- package/skill/examples/hello-host-js/home/pages/home/index.tsx +15 -0
- package/skill/examples/hello-host-js/lingxia.yaml +39 -0
- package/skill/examples/hello-host-rust/Cargo.toml +15 -0
- package/skill/examples/hello-host-rust/README.md +44 -0
- package/skill/examples/hello-host-rust/home/lxapp.json +13 -0
- package/skill/examples/hello-host-rust/home/pages/home/index.html +46 -0
- package/skill/examples/hello-host-rust/home/pages/home/index.json +4 -0
- package/skill/examples/hello-host-rust/lingxia.yaml +32 -0
- package/skill/examples/hello-host-rust/src/lib.rs +58 -0
- package/skill/examples/hello-lxapp/README.md +29 -0
- package/skill/examples/hello-lxapp/lxapp.config.ts +8 -0
- package/skill/examples/hello-lxapp/lxapp.json +14 -0
- package/skill/examples/hello-lxapp/package.json +14 -0
- package/skill/examples/hello-lxapp/pages/home/index.json +4 -0
- package/skill/examples/hello-lxapp/pages/home/index.ts +35 -0
- package/skill/examples/hello-lxapp/pages/home/index.tsx +34 -0
- package/skill/lxapp/bridge.md +654 -0
- package/skill/lxapp/components.md +375 -0
- package/skill/lxapp/guide.md +675 -0
- package/skill/lxapp/lx-api.md +481 -0
- package/skill/native/development.md +414 -0
- package/skill/reference/file-lifecycle.md +325 -0
- package/skill/skill-manifest.json +6 -0
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
# Native Components
|
|
2
|
+
|
|
3
|
+
LingXia ships a set of native-backed components for lxapp views: `LxInput`, `LxTextarea`, `LxPicker`, `LxVideo`, `LxMediaSwiper`, `LxNavigator`. They render as platform-native UI under the WebView and are wired into the bridge so events can route directly to Logic.
|
|
4
|
+
|
|
5
|
+
The components live in `@lingxia/elements` (the pure-JS custom elements) and are re-exported as framework-friendly wrappers from `@lingxia/react`, `@lingxia/vue`, and `@lingxia/html`. **Almost always import from the framework package**, not from `@lingxia/elements`.
|
|
6
|
+
|
|
7
|
+
For framework wiring (event short-path vs. View DOM path, `useLxPage` shape) see [`./guide.md`](./guide.md).
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Import shape
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// React
|
|
15
|
+
import { LxInput, LxVideo, LxPicker, LxMediaSwiper, LxNavigator, LxTextarea } from '@lingxia/react';
|
|
16
|
+
|
|
17
|
+
// Vue
|
|
18
|
+
import { LxInput, LxVideo, LxPicker, LxMediaSwiper, LxNavigator, LxTextarea } from '@lingxia/vue';
|
|
19
|
+
|
|
20
|
+
// HTML (custom-element registration runs automatically when @lingxia/html is loaded)
|
|
21
|
+
// Use the tag names directly in markup: <lx-input>, <lx-video>, <lx-picker>, <lx-media-swiper>, <lx-navigator>, <lx-textarea>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The React/Vue wrappers accept all the underlying attributes (camelCase or kebab-case where noted) plus the framework's standard `className` / `class` / `style` / `ref`.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Callback shapes by component
|
|
29
|
+
|
|
30
|
+
A common source of confusion: not every component passes the same thing to its event handler. The framework wrappers unwrap or reshape some events; others come through as raw DOM `CustomEvent`. Keep this table handy:
|
|
31
|
+
|
|
32
|
+
| Component | What the handler receives | Example |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `LxInput` / `LxTextarea` | **Unwrapped `event.detail` object** (`LxInputEventDetail`) | `onInput(detail)` → `detail.value`, `detail.cursor`, … |
|
|
35
|
+
| `LxPicker` | **Resolved value directly** — `string \| string[]` for selectors, or full `LxPickerEventDetail` on `onChange` | `onConfirm(value)` |
|
|
36
|
+
| `LxVideo` | **Raw DOM `Event`** | `onPlaying(event)` → `event.detail` |
|
|
37
|
+
| `LxMediaSwiper` | **Raw DOM `CustomEvent`** with a typed `detail` | `onChange(event)` → `event.detail.index` |
|
|
38
|
+
| `LxNavigator` | Raw DOM `CustomEvent` | `onSuccess(event)` → `event.detail.success` |
|
|
39
|
+
|
|
40
|
+
When in doubt: log the value once, or read the component's type export below.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## `LxInput`
|
|
45
|
+
|
|
46
|
+
Single-line input, backed by the native input field.
|
|
47
|
+
|
|
48
|
+
**Attributes (`LxInputAttributes`):**
|
|
49
|
+
|
|
50
|
+
| Attribute | Type | Notes |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| `id` | `string` | Used by Logic-side `lx.createSelectorQuery()` if you need it. |
|
|
53
|
+
| `value` | `string` | Two-way: pass `data.value` and update from a Logic handler. |
|
|
54
|
+
| `type` | `'text' \| 'number' \| 'password' \| 'digit'` | |
|
|
55
|
+
| `placeholder` | `string` | |
|
|
56
|
+
| `placeholder-style` / `placeholder-class` | `string` | Styling hooks for the placeholder. |
|
|
57
|
+
| `maxlength` | `number \| string` | |
|
|
58
|
+
| `disabled` | `boolean \| string` | |
|
|
59
|
+
| `focus` | `boolean \| string` | Set true to programmatically focus. |
|
|
60
|
+
| `auto-focus` | `boolean \| string` | |
|
|
61
|
+
| `confirm-type` | `'send' \| 'search' \| 'next' \| 'go' \| 'done'` | Keyboard return key label. |
|
|
62
|
+
| `confirm-hold` | `boolean \| string` | Keep keyboard open after confirm. |
|
|
63
|
+
| `cursor`, `cursor-spacing`, `cursor-color` | varied | Cursor position and styling. |
|
|
64
|
+
| `selection-start` / `selection-end` | `number \| string` | Initial selection range. |
|
|
65
|
+
| `adjust-position` | `boolean \| string` | Auto-scroll page so input stays above keyboard. |
|
|
66
|
+
| `hold-keyboard` | `boolean \| string` | |
|
|
67
|
+
| `password` | `boolean \| string` | Legacy alias for `type="password"`. |
|
|
68
|
+
|
|
69
|
+
**Events** — handler receives `LxInputEventDetail`:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
interface LxInputEventDetail {
|
|
73
|
+
value?: string;
|
|
74
|
+
cursor?: number;
|
|
75
|
+
keyCode?: number;
|
|
76
|
+
height?: number; // keyboard height (onKeyboardheightchange)
|
|
77
|
+
duration?: number;
|
|
78
|
+
encryptedValue?: string;
|
|
79
|
+
encryptError?: string;
|
|
80
|
+
pass?: boolean;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
| Event prop | Fires on |
|
|
85
|
+
|---|---|
|
|
86
|
+
| `onInput` | every character change |
|
|
87
|
+
| `onChange` | value committed (e.g. blur on some platforms) |
|
|
88
|
+
| `onFocus` / `onBlur` | focus state change |
|
|
89
|
+
| `onConfirm` | keyboard return key pressed |
|
|
90
|
+
| `onKeyboardheightchange` | software keyboard resize |
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<LxInput
|
|
94
|
+
value={data.email}
|
|
95
|
+
type="text"
|
|
96
|
+
placeholder="you@example.com"
|
|
97
|
+
onInput={actions.onEmailInput} // (detail) => void
|
|
98
|
+
onConfirm={actions.onSubmit}
|
|
99
|
+
/>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## `LxTextarea`
|
|
105
|
+
|
|
106
|
+
Multi-line input. Same event detail shape as `LxInput` plus `onLinechange`.
|
|
107
|
+
|
|
108
|
+
**Notable attributes beyond `LxInput`:**
|
|
109
|
+
|
|
110
|
+
| Attribute | Type | Notes |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| `auto-height` | `boolean \| string` | Grow with content. |
|
|
113
|
+
| `show-confirm-bar` | `boolean \| string` | Toolbar above keyboard. |
|
|
114
|
+
| `disable-default-padding` | `boolean \| string` | |
|
|
115
|
+
| `fixed` | `boolean \| string` | For use inside scroll containers. |
|
|
116
|
+
| `adjust-keyboard-to` | `'cursor' \| 'bottom'` | Keyboard avoidance anchor. |
|
|
117
|
+
| `confirm-type` | adds `'return'` over `LxInput` | |
|
|
118
|
+
|
|
119
|
+
**Extra event:**
|
|
120
|
+
|
|
121
|
+
- `onLinechange` — fires when line count changes (when `auto-height` is on).
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## `LxPicker`
|
|
126
|
+
|
|
127
|
+
Native picker with several modes.
|
|
128
|
+
|
|
129
|
+
**Modes (`mode` attribute):**
|
|
130
|
+
|
|
131
|
+
| Mode | Columns shape | Confirm value type |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| `selector` (default) | `string[]` (one column) | `string` |
|
|
134
|
+
| `multiSelector` | `string[][]` (parallel columns) | `string[]` |
|
|
135
|
+
| `cascading` | `LxPickerCascadingColumns` (tree) | `string[]` |
|
|
136
|
+
| `date` | configured via `fields`, `start`, `end` | `string` (`YYYY-MM-DD`) |
|
|
137
|
+
| `time` | hours/minutes | `string` (`HH:mm`) |
|
|
138
|
+
|
|
139
|
+
**Key attributes:**
|
|
140
|
+
|
|
141
|
+
| Attribute | Type | Notes |
|
|
142
|
+
|---|---|---|
|
|
143
|
+
| `mode` | one of above | |
|
|
144
|
+
| `columns` | `LxPickerColumn[] \| LxPickerCascadingColumns` | Required for selector / multiSelector / cascading. |
|
|
145
|
+
| `defaultIndex` | `number \| number[]` | Initial selected index(es). |
|
|
146
|
+
| `value` | `string` | Initial date/time for `date`/`time` modes. |
|
|
147
|
+
| `start` / `end` | `string` | Date/time range bounds. |
|
|
148
|
+
| `fields` | `'year' \| 'month' \| 'day' \| 'range'` | Date mode granularity. |
|
|
149
|
+
| `cancelText` / `confirmText` | `string` | Button labels. |
|
|
150
|
+
| `cancelButtonColor` / `confirmButtonColor` / `cancelTextColor` / `confirmTextColor` | `string` (hex) | Styling. |
|
|
151
|
+
|
|
152
|
+
**Event handler shapes:**
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
// onChange (scroll-time updates) — receives the FULL detail
|
|
156
|
+
type LxPickerEventDetail = {
|
|
157
|
+
index?: number | number[];
|
|
158
|
+
value?: string | string[];
|
|
159
|
+
confirmed?: boolean;
|
|
160
|
+
cancelled?: boolean;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// onConfirm — receives the resolved VALUE directly (the framework wrapper unwraps it)
|
|
164
|
+
// value: string for `selector` / `date` / `time`; string[] for `multiSelector` / `cascading`
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
<LxPicker
|
|
169
|
+
mode="multiSelector"
|
|
170
|
+
columns={[
|
|
171
|
+
['China', 'USA'],
|
|
172
|
+
['Beijing', 'Shanghai'],
|
|
173
|
+
]}
|
|
174
|
+
defaultIndex={[0, 0]}
|
|
175
|
+
onConfirm={(value) => actions.setCity({ value })}
|
|
176
|
+
onChange={(detail) => console.log('scrolling', detail.index)}
|
|
177
|
+
/>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## `LxVideo`
|
|
183
|
+
|
|
184
|
+
Native video player.
|
|
185
|
+
|
|
186
|
+
**Attributes (`LxVideoAttributes`):**
|
|
187
|
+
|
|
188
|
+
| Attribute | Type | Notes |
|
|
189
|
+
|---|---|---|
|
|
190
|
+
| `id` | `string` | Pass to `lx.createVideoContext(id)` in Logic to imperatively control the player. |
|
|
191
|
+
| `src` | `string` | Video URL. Must be under `security.network.trustedDomains` if remote. |
|
|
192
|
+
| `poster` | `string` | Cover image URL. |
|
|
193
|
+
| `objectFit` | `'cover' \| 'contain' \| 'fill' \| 'fit'` | |
|
|
194
|
+
| `contentRotate` | `0 \| 90 \| 180 \| 270` | |
|
|
195
|
+
| `autoplay` / `loop` / `muted` | `boolean` | |
|
|
196
|
+
| `controls` | `boolean` | Show native controls UI. |
|
|
197
|
+
| `progressBar` | `boolean` | Show progress bar (subset of controls). |
|
|
198
|
+
| `live` | `boolean` | Live-stream mode (disables seek). |
|
|
199
|
+
| `volume` | `string \| number` | 0–1. |
|
|
200
|
+
| `qualities` | `LxVideoQuality[]` (`{ label, url? }`) | First item is the default quality. |
|
|
201
|
+
| `playbackRates` | `number[]` | First item is the default rate. |
|
|
202
|
+
|
|
203
|
+
**Events** — every handler receives a **raw DOM `Event`**. The native player encodes data on `event.detail`.
|
|
204
|
+
|
|
205
|
+
| Event prop | Meaning |
|
|
206
|
+
|---|---|
|
|
207
|
+
| `onPlayRequest` | user tapped play (before playback starts) |
|
|
208
|
+
| `onPlay` | playback started |
|
|
209
|
+
| `onPlaying` | playback resumed/buffering ended |
|
|
210
|
+
| `onPause` | paused |
|
|
211
|
+
| `onStop` | stopped |
|
|
212
|
+
| `onEnded` | reached end |
|
|
213
|
+
| `onTimeUpdate` | progress update — read `event.detail.currentTime` |
|
|
214
|
+
| `onError` | playback failed — read `event.detail.code` / `event.detail.message` |
|
|
215
|
+
| `onLoadedMetadata` | metadata available — `event.detail.duration`, `width`, `height` |
|
|
216
|
+
| `onFullscreenChange` | entered/exited fullscreen — `event.detail.fullScreen` |
|
|
217
|
+
| `onWaiting` | buffering |
|
|
218
|
+
| `onQualityChange` | user picked a different quality entry |
|
|
219
|
+
| `onRateChange` | user picked a different playback rate |
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
<LxVideo
|
|
223
|
+
id="hero"
|
|
224
|
+
src="https://cdn.example.com/intro.mp4"
|
|
225
|
+
poster="https://cdn.example.com/intro.jpg"
|
|
226
|
+
controls
|
|
227
|
+
qualities={[
|
|
228
|
+
{ label: '1080p', url: 'https://cdn.example.com/intro-1080.mp4' },
|
|
229
|
+
{ label: '720p', url: 'https://cdn.example.com/intro-720.mp4' },
|
|
230
|
+
]}
|
|
231
|
+
playbackRates={[1.0, 1.5, 2.0]}
|
|
232
|
+
onTimeUpdate={actions.onProgress} // (event) => { event.detail.currentTime }
|
|
233
|
+
onError={actions.onVideoError}
|
|
234
|
+
/>
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Imperative control from Logic** (`pages/.../index.ts`):
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
const ctx = lx.createVideoContext('hero');
|
|
241
|
+
ctx.play();
|
|
242
|
+
ctx.pause();
|
|
243
|
+
ctx.seek(30); // seconds
|
|
244
|
+
ctx.requestFullScreen();
|
|
245
|
+
ctx.exitFullScreen();
|
|
246
|
+
ctx.setStreamSource({ /* … */ });
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## `LxMediaSwiper`
|
|
252
|
+
|
|
253
|
+
Carousel for images and videos with native paging.
|
|
254
|
+
|
|
255
|
+
**Attributes (`LxMediaSwiperAttributes`):**
|
|
256
|
+
|
|
257
|
+
| Attribute | Type | Notes |
|
|
258
|
+
|---|---|---|
|
|
259
|
+
| `items` | `LxMediaSwiperItem[]` | See item shape below. |
|
|
260
|
+
| `index` | `number` | Controlled current index. |
|
|
261
|
+
| `initialIndex` | `number` | Uncontrolled initial index. |
|
|
262
|
+
| `loop` | `boolean` | |
|
|
263
|
+
| `autoplay` / `interval` | `boolean` / `number (ms)` | |
|
|
264
|
+
| `animation` | `'slide' \| 'none'` | |
|
|
265
|
+
| `animationDuration` | `number` | ms |
|
|
266
|
+
| `direction` | `'horizontal' \| 'vertical'` | |
|
|
267
|
+
| `contentRotate` / `objectFit` | same as `LxVideo` | |
|
|
268
|
+
| `controls` / `muted` | `boolean` | Forwarded to video items. |
|
|
269
|
+
| `dots` | `boolean \| { color?, activeColor? }` | Page indicator. |
|
|
270
|
+
| `swipeEnabled` | `boolean` | |
|
|
271
|
+
| `peek` | `LxMediaSwiperPeek` | Show adjacent items. |
|
|
272
|
+
|
|
273
|
+
**Item shape:**
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
type LxMediaSwiperItem =
|
|
277
|
+
| { id?: string; type: 'image'; src: string }
|
|
278
|
+
| { id?: string; type: 'video'; src: string; poster?: string; controls?: boolean; muted?: boolean };
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Events** — handler receives `CustomEvent<...EventDetail>`. Read `event.detail`.
|
|
282
|
+
|
|
283
|
+
| Event | `event.detail` shape |
|
|
284
|
+
|---|---|
|
|
285
|
+
| `onChange` | `{ index, previousIndex, item, source: 'touch' \| 'autoplay' \| 'api' \| 'video' }` |
|
|
286
|
+
| `onTransitionEnd` | same as `onChange` |
|
|
287
|
+
| `onTap` | `{ index, item }` |
|
|
288
|
+
| `onVideoEnded` | `{ index, item }` |
|
|
289
|
+
| `onEndReached` | `{ index, item, source }` — fires when the user reaches the last item |
|
|
290
|
+
| `onError` | `{ index, item, code: 'not_found' \| 'network' \| 'decode' \| … }` |
|
|
291
|
+
|
|
292
|
+
```tsx
|
|
293
|
+
<LxMediaSwiper
|
|
294
|
+
items={[
|
|
295
|
+
{ type: 'image', src: 'https://cdn.example.com/a.jpg' },
|
|
296
|
+
{ type: 'video', src: 'https://cdn.example.com/b.mp4', controls: true },
|
|
297
|
+
]}
|
|
298
|
+
loop
|
|
299
|
+
dots
|
|
300
|
+
onChange={(e) => actions.onSlideChange({ index: e.detail.index })}
|
|
301
|
+
onEndReached={actions.loadMore}
|
|
302
|
+
/>
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## `LxNavigator`
|
|
308
|
+
|
|
309
|
+
Declarative navigation — wraps content that, when tapped, navigates inside or outside the lxapp.
|
|
310
|
+
|
|
311
|
+
**Open types** (`open-type`):
|
|
312
|
+
|
|
313
|
+
| Value | Behavior |
|
|
314
|
+
|---|---|
|
|
315
|
+
| `navigate` (default) | Push a new page in the current lxapp |
|
|
316
|
+
| `redirect` | Replace the current page |
|
|
317
|
+
| `navigateBack` | Pop back; use `delta` for distance |
|
|
318
|
+
| `reLaunch` | Restart the app at a new page |
|
|
319
|
+
| `switchTab` | Switch to a tab page |
|
|
320
|
+
| `exit` | Exit the current lxapp |
|
|
321
|
+
| `openUrl` | Open an external URL (or another lxapp) |
|
|
322
|
+
| `tel` | Trigger a phone call (use with `phone-number`) |
|
|
323
|
+
|
|
324
|
+
**Targets** (`target`): `self` (default), `lxapp`, `browser`.
|
|
325
|
+
|
|
326
|
+
**Attributes:**
|
|
327
|
+
|
|
328
|
+
| Attribute | Use |
|
|
329
|
+
|---|---|
|
|
330
|
+
| `url` | Browser URL for `openUrl` / `browser` target |
|
|
331
|
+
| `page` | Named page in `lxapp.json` |
|
|
332
|
+
| `path` | Raw page path; supports query string |
|
|
333
|
+
| `query` | JSON-encoded page query params |
|
|
334
|
+
| `open-type` | one of the above |
|
|
335
|
+
| `target` | one of the above (auto-inferred if omitted) |
|
|
336
|
+
| `delta` | how many pages to pop for `navigateBack` |
|
|
337
|
+
| `app-id` | target lxapp ID for cross-app navigation |
|
|
338
|
+
| `env-version` | `'release' \| 'preview' \| 'develop'` |
|
|
339
|
+
| `target-version` | exact target lxapp version |
|
|
340
|
+
| `phone-number` | required for `open-type="tel"` |
|
|
341
|
+
|
|
342
|
+
**Events:**
|
|
343
|
+
|
|
344
|
+
- `onSuccess` / `onFail` / `onComplete` — `event.detail` is `{ success?: boolean; errMsg?: string }`.
|
|
345
|
+
|
|
346
|
+
```tsx
|
|
347
|
+
<LxNavigator page="detail" query='{"id":42}' onFail={actions.onNavFail}>
|
|
348
|
+
<div>Open detail</div>
|
|
349
|
+
</LxNavigator>
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
For imperative navigation from Logic, use the `lx.navigateTo({...})` family — see [`./lx-api.md`](./lx-api.md).
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## Two event paths (recap)
|
|
357
|
+
|
|
358
|
+
LingXia components support two delivery paths:
|
|
359
|
+
|
|
360
|
+
1. **Logic short path** (native → Rust → Logic JS, 3 hops). Used when the handler you pass is one of `useLxPage().actions`. The CLI auto-generates `pageFuncBindings` so events route to Logic directly, skipping the WebView roundtrip.
|
|
361
|
+
2. **View DOM path** (native → WebView `CustomEvent` → handler, 2 hops). Used when the handler is a local View function (e.g., a React `useState` setter).
|
|
362
|
+
|
|
363
|
+
You don't pick between them. Pass an `actions.foo` and you get the short path; pass a local function and you get the DOM path.
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Where these wrappers come from
|
|
368
|
+
|
|
369
|
+
- **Pure JS custom elements** live in `@lingxia/elements` (`registerInputComponent`, `LxInputElement`, etc.). Importing `@lingxia/elements` registers `<lx-input>`, `<lx-video>`, … into `customElements`.
|
|
370
|
+
- **React wrappers** (`@lingxia/react`) wrap each custom element with prop-to-attribute translation and `pageBindings` injection.
|
|
371
|
+
- **Vue wrappers** (`@lingxia/vue`) do the same for Vue's reactivity.
|
|
372
|
+
- **HTML** views use the custom elements directly — `@lingxia/html` only handles page state / actions (`subscribe`, `getActions`).
|
|
373
|
+
|
|
374
|
+
For attributes not listed here (rare, mostly low-level styling escape hatches), the underlying types are exported from `@lingxia/elements`:
|
|
375
|
+
`LxInputAttributes`, `LxTextareaAttributes`, `LxPickerAttributes`, `LxVideoAttributes`, `LxMediaSwiperAttributes`, `LxNavigatorAttributes`, plus matching `*EventDetail` and `*Event` types.
|