@lingxia/page-runtime 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/shared/runtime.d.ts +1 -12
- package/dist/shared/runtime.js +72 -43
- package/package.json +6 -32
- package/dist/react/LxInput.d.ts +0 -47
- package/dist/react/LxInput.js +0 -128
- package/dist/react/LxNavigator.d.ts +0 -23
- package/dist/react/LxNavigator.js +0 -61
- package/dist/react/LxPicker.d.ts +0 -27
- package/dist/react/LxPicker.js +0 -113
- package/dist/react/LxTextarea.d.ts +0 -47
- package/dist/react/LxTextarea.js +0 -118
- package/dist/react/LxVideo.d.ts +0 -5
- package/dist/react/LxVideo.js +0 -113
- package/dist/react/hook.d.ts +0 -39
- package/dist/react/hook.js +0 -212
- package/dist/react/index.d.ts +0 -6
- package/dist/react/index.js +0 -6
- package/dist/react/text_component_shared.d.ts +0 -5
- package/dist/react/text_component_shared.js +0 -33
- package/dist/vue/LxInput.vue +0 -92
- package/dist/vue/LxNavigator.vue +0 -79
- package/dist/vue/LxPicker.vue +0 -144
- package/dist/vue/LxTextarea.vue +0 -90
- package/dist/vue/LxVideo.vue +0 -111
- package/dist/vue/hook.d.ts +0 -42
- package/dist/vue/hook.js +0 -194
- package/dist/vue/index.d.ts +0 -7
- package/dist/vue/index.js +0 -6
- package/dist/vue/text_component_shared.d.ts +0 -3
- package/dist/vue/text_component_shared.js +0 -26
- package/dist/vue/types.d.ts +0 -101
- package/dist/vue/types.js +0 -1
- package/src/index.ts +0 -21
- package/src/react/LxInput.tsx +0 -224
- package/src/react/LxNavigator.tsx +0 -132
- package/src/react/LxPicker.tsx +0 -205
- package/src/react/LxTextarea.tsx +0 -216
- package/src/react/LxVideo.tsx +0 -166
- package/src/react/hook.ts +0 -317
- package/src/react/index.ts +0 -14
- package/src/react/text_component_shared.ts +0 -43
- package/src/shared/runtime.ts +0 -186
- package/src/vue/LxInput.vue +0 -92
- package/src/vue/LxNavigator.vue +0 -79
- package/src/vue/LxPicker.vue +0 -144
- package/src/vue/LxTextarea.vue +0 -90
- package/src/vue/LxVideo.vue +0 -111
- package/src/vue/hook.ts +0 -313
- package/src/vue/index.ts +0 -22
- package/src/vue/shims-vue.d.ts +0 -5
- package/src/vue/text_component_shared.ts +0 -33
- package/src/vue/types.ts +0 -107
package/src/react/LxTextarea.tsx
DELETED
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import React, { forwardRef, useCallback, useEffect, useRef } from "react";
|
|
2
|
-
import { registerTextareaComponent } from "@lingxia/elements";
|
|
3
|
-
import { buildTextareaNativeAttrs } from "@lingxia/elements";
|
|
4
|
-
import {
|
|
5
|
-
assignForwardedRef,
|
|
6
|
-
bindElementEvents,
|
|
7
|
-
getCustomEventDetail,
|
|
8
|
-
unbindElementEvents,
|
|
9
|
-
} from "./text_component_shared.js";
|
|
10
|
-
|
|
11
|
-
export interface LxTextareaEventDetail {
|
|
12
|
-
value?: string;
|
|
13
|
-
cursor?: number;
|
|
14
|
-
lineCount?: number;
|
|
15
|
-
height?: number;
|
|
16
|
-
duration?: number;
|
|
17
|
-
selectionStart?: number;
|
|
18
|
-
selectionEnd?: number;
|
|
19
|
-
heightRpx?: number;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface LxTextareaProps {
|
|
23
|
-
id?: string;
|
|
24
|
-
value?: string;
|
|
25
|
-
defaultValue?: string;
|
|
26
|
-
placeholder?: string;
|
|
27
|
-
placeholderStyle?: string;
|
|
28
|
-
placeholderClass?: string;
|
|
29
|
-
maxlength?: number;
|
|
30
|
-
disabled?: boolean;
|
|
31
|
-
autoFocus?: boolean;
|
|
32
|
-
focus?: boolean;
|
|
33
|
-
autoHeight?: boolean;
|
|
34
|
-
cursorSpacing?: number;
|
|
35
|
-
showConfirmBar?: boolean;
|
|
36
|
-
adjustPosition?: boolean;
|
|
37
|
-
holdKeyboard?: boolean;
|
|
38
|
-
disableDefaultPadding?: boolean;
|
|
39
|
-
confirmType?: "send" | "search" | "next" | "go" | "done" | "return";
|
|
40
|
-
confirmHold?: boolean;
|
|
41
|
-
fixed?: boolean;
|
|
42
|
-
adjustKeyboardTo?: "cursor" | "bottom";
|
|
43
|
-
cursor?: number;
|
|
44
|
-
selectionStart?: number;
|
|
45
|
-
selectionEnd?: number;
|
|
46
|
-
|
|
47
|
-
onInput?: (detail: LxTextareaEventDetail) => void;
|
|
48
|
-
onChange?: (detail: LxTextareaEventDetail) => void;
|
|
49
|
-
onFocus?: (detail: LxTextareaEventDetail) => void;
|
|
50
|
-
onBlur?: (detail: LxTextareaEventDetail) => void;
|
|
51
|
-
onConfirm?: (detail: LxTextareaEventDetail) => void;
|
|
52
|
-
onLineChange?: (detail: LxTextareaEventDetail) => void;
|
|
53
|
-
onKeyboardHeightChange?: (detail: LxTextareaEventDetail) => void;
|
|
54
|
-
|
|
55
|
-
// Logic bindings (CLI-generated)
|
|
56
|
-
pageBindings?: Record<string, string>;
|
|
57
|
-
|
|
58
|
-
className?: string;
|
|
59
|
-
style?: React.CSSProperties;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (typeof window !== "undefined") {
|
|
63
|
-
registerTextareaComponent();
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export const LxTextarea = forwardRef<HTMLElement, LxTextareaProps>(({
|
|
67
|
-
value,
|
|
68
|
-
defaultValue,
|
|
69
|
-
placeholder,
|
|
70
|
-
placeholderStyle,
|
|
71
|
-
placeholderClass,
|
|
72
|
-
maxlength,
|
|
73
|
-
disabled,
|
|
74
|
-
autoFocus,
|
|
75
|
-
focus,
|
|
76
|
-
autoHeight,
|
|
77
|
-
cursorSpacing,
|
|
78
|
-
showConfirmBar,
|
|
79
|
-
adjustPosition,
|
|
80
|
-
holdKeyboard,
|
|
81
|
-
disableDefaultPadding,
|
|
82
|
-
confirmType,
|
|
83
|
-
confirmHold,
|
|
84
|
-
fixed,
|
|
85
|
-
adjustKeyboardTo,
|
|
86
|
-
cursor,
|
|
87
|
-
selectionStart,
|
|
88
|
-
selectionEnd,
|
|
89
|
-
onInput,
|
|
90
|
-
onChange,
|
|
91
|
-
onFocus,
|
|
92
|
-
onBlur,
|
|
93
|
-
onConfirm,
|
|
94
|
-
onLineChange,
|
|
95
|
-
onKeyboardHeightChange,
|
|
96
|
-
pageBindings,
|
|
97
|
-
className,
|
|
98
|
-
style,
|
|
99
|
-
id,
|
|
100
|
-
...rest
|
|
101
|
-
}, ref) => {
|
|
102
|
-
const elementRef = useRef<HTMLElement | null>(null);
|
|
103
|
-
const boundElementRef = useRef<HTMLElement | null>(null);
|
|
104
|
-
const handlerRef = useRef({
|
|
105
|
-
onInput,
|
|
106
|
-
onChange,
|
|
107
|
-
onFocus,
|
|
108
|
-
onBlur,
|
|
109
|
-
onConfirm,
|
|
110
|
-
onLineChange,
|
|
111
|
-
onKeyboardHeightChange,
|
|
112
|
-
});
|
|
113
|
-
handlerRef.current = {
|
|
114
|
-
onInput,
|
|
115
|
-
onChange,
|
|
116
|
-
onFocus,
|
|
117
|
-
onBlur,
|
|
118
|
-
onConfirm,
|
|
119
|
-
onLineChange,
|
|
120
|
-
onKeyboardHeightChange,
|
|
121
|
-
};
|
|
122
|
-
const listenerMapRef = useRef<Record<string, EventListenerObject>>({
|
|
123
|
-
input: {
|
|
124
|
-
handleEvent: (event: Event) => handlerRef.current.onInput?.(getCustomEventDetail<LxTextareaEventDetail>(event)),
|
|
125
|
-
},
|
|
126
|
-
change: {
|
|
127
|
-
handleEvent: (event: Event) => handlerRef.current.onChange?.(getCustomEventDetail<LxTextareaEventDetail>(event)),
|
|
128
|
-
},
|
|
129
|
-
focus: {
|
|
130
|
-
handleEvent: (event: Event) => handlerRef.current.onFocus?.(getCustomEventDetail<LxTextareaEventDetail>(event)),
|
|
131
|
-
},
|
|
132
|
-
blur: {
|
|
133
|
-
handleEvent: (event: Event) => handlerRef.current.onBlur?.(getCustomEventDetail<LxTextareaEventDetail>(event)),
|
|
134
|
-
},
|
|
135
|
-
confirm: {
|
|
136
|
-
handleEvent: (event: Event) => handlerRef.current.onConfirm?.(getCustomEventDetail<LxTextareaEventDetail>(event)),
|
|
137
|
-
},
|
|
138
|
-
linechange: {
|
|
139
|
-
handleEvent: (event: Event) => handlerRef.current.onLineChange?.(getCustomEventDetail<LxTextareaEventDetail>(event)),
|
|
140
|
-
},
|
|
141
|
-
keyboardheightchange: {
|
|
142
|
-
handleEvent: (event: Event) => handlerRef.current.onKeyboardHeightChange?.(getCustomEventDetail<LxTextareaEventDetail>(event)),
|
|
143
|
-
},
|
|
144
|
-
});
|
|
145
|
-
const elementRefCallback = useCallback((element: HTMLElement | null) => {
|
|
146
|
-
boundElementRef.current = bindElementEvents(boundElementRef.current, element, listenerMapRef.current);
|
|
147
|
-
elementRef.current = element;
|
|
148
|
-
assignForwardedRef(ref, element);
|
|
149
|
-
}, [ref]);
|
|
150
|
-
|
|
151
|
-
useEffect(() => () => {
|
|
152
|
-
unbindElementEvents(boundElementRef.current, listenerMapRef.current);
|
|
153
|
-
boundElementRef.current = null;
|
|
154
|
-
elementRef.current = null;
|
|
155
|
-
}, []);
|
|
156
|
-
|
|
157
|
-
React.useEffect(() => {
|
|
158
|
-
const el = elementRef.current;
|
|
159
|
-
if (!el) return;
|
|
160
|
-
const setAttr = (name: string, next: string | null) => {
|
|
161
|
-
if (next === null) {
|
|
162
|
-
el.removeAttribute(name);
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
el.setAttribute(name, next);
|
|
166
|
-
};
|
|
167
|
-
setAttr("value", value !== undefined ? String(value) : null);
|
|
168
|
-
setAttr("focus", focus !== undefined ? (focus ? "true" : "false") : null);
|
|
169
|
-
setAttr("maxlength", maxlength !== undefined ? String(maxlength) : null);
|
|
170
|
-
setAttr("placeholder-style", placeholderStyle ? String(placeholderStyle) : null);
|
|
171
|
-
setAttr("auto-height", autoHeight ? "true" : null);
|
|
172
|
-
}, [value, focus, maxlength, placeholderStyle, autoHeight]);
|
|
173
|
-
|
|
174
|
-
// Set pageBindings property on custom element
|
|
175
|
-
useEffect(() => {
|
|
176
|
-
const el = elementRef.current as any;
|
|
177
|
-
if (el && pageBindings) {
|
|
178
|
-
el.pageBindings = pageBindings;
|
|
179
|
-
}
|
|
180
|
-
}, [pageBindings]);
|
|
181
|
-
|
|
182
|
-
const textareaProps = buildTextareaNativeAttrs({
|
|
183
|
-
id,
|
|
184
|
-
value,
|
|
185
|
-
defaultValue,
|
|
186
|
-
placeholder,
|
|
187
|
-
placeholderStyle,
|
|
188
|
-
placeholderClass,
|
|
189
|
-
maxlength,
|
|
190
|
-
disabled,
|
|
191
|
-
autoFocus,
|
|
192
|
-
focus,
|
|
193
|
-
autoHeight,
|
|
194
|
-
cursorSpacing,
|
|
195
|
-
showConfirmBar,
|
|
196
|
-
adjustPosition,
|
|
197
|
-
holdKeyboard,
|
|
198
|
-
disableDefaultPadding,
|
|
199
|
-
confirmType,
|
|
200
|
-
confirmHold,
|
|
201
|
-
fixed,
|
|
202
|
-
adjustKeyboardTo,
|
|
203
|
-
cursor,
|
|
204
|
-
selectionStart,
|
|
205
|
-
selectionEnd,
|
|
206
|
-
}, rest as Record<string, unknown>, boundElementRef.current !== null);
|
|
207
|
-
|
|
208
|
-
return React.createElement("lx-textarea", {
|
|
209
|
-
ref: elementRefCallback,
|
|
210
|
-
className,
|
|
211
|
-
style,
|
|
212
|
-
...textareaProps,
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
LxTextarea.displayName = "LxTextarea";
|
package/src/react/LxVideo.tsx
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import React, { forwardRef, useCallback, useEffect, useId, useMemo, useRef } from 'react';
|
|
2
|
-
import { registerVideoComponent, type LxVideoAttributes } from '@lingxia/elements';
|
|
3
|
-
import {
|
|
4
|
-
buildVideoNativeAttrs,
|
|
5
|
-
VIDEO_DOM_EVENT_MAP,
|
|
6
|
-
} from '@lingxia/elements';
|
|
7
|
-
import {
|
|
8
|
-
assignForwardedRef,
|
|
9
|
-
bindElementEvents,
|
|
10
|
-
unbindElementEvents,
|
|
11
|
-
} from './text_component_shared.js';
|
|
12
|
-
|
|
13
|
-
export interface LxVideoProps
|
|
14
|
-
extends LxVideoAttributes,
|
|
15
|
-
Omit<
|
|
16
|
-
React.HTMLAttributes<HTMLElement>,
|
|
17
|
-
keyof LxVideoAttributes | "children" | "dangerouslySetInnerHTML" | "ref" | "onPlaying"
|
|
18
|
-
> {}
|
|
19
|
-
|
|
20
|
-
if (typeof window !== "undefined") {
|
|
21
|
-
registerVideoComponent();
|
|
22
|
-
}
|
|
23
|
-
export const LxVideo = forwardRef<HTMLElement, LxVideoProps>(({
|
|
24
|
-
id,
|
|
25
|
-
src,
|
|
26
|
-
poster,
|
|
27
|
-
objectFit,
|
|
28
|
-
rotate,
|
|
29
|
-
autoplay,
|
|
30
|
-
loop,
|
|
31
|
-
muted,
|
|
32
|
-
controls,
|
|
33
|
-
progressBar,
|
|
34
|
-
live,
|
|
35
|
-
volume,
|
|
36
|
-
qualities,
|
|
37
|
-
playbackRates,
|
|
38
|
-
onPlayRequest,
|
|
39
|
-
onPlay,
|
|
40
|
-
onPlaying,
|
|
41
|
-
onPause,
|
|
42
|
-
onStop,
|
|
43
|
-
onEnded,
|
|
44
|
-
onTimeUpdate,
|
|
45
|
-
onError,
|
|
46
|
-
onLoadedMetadata,
|
|
47
|
-
onFullscreenChange,
|
|
48
|
-
onWaiting,
|
|
49
|
-
onQualityChange,
|
|
50
|
-
onRateChange,
|
|
51
|
-
pageBindings,
|
|
52
|
-
className,
|
|
53
|
-
style,
|
|
54
|
-
...rest
|
|
55
|
-
}, ref) => {
|
|
56
|
-
const elementRef = useRef<HTMLElement | null>(null);
|
|
57
|
-
const boundElementRef = useRef<HTMLElement | null>(null);
|
|
58
|
-
const reactId = useId();
|
|
59
|
-
const resolvedId = useMemo(() => {
|
|
60
|
-
if (id) return id;
|
|
61
|
-
return `lx-video-${reactId.replace(/[:]/g, "")}`;
|
|
62
|
-
}, [id, reactId]);
|
|
63
|
-
const handlerRef = useRef({
|
|
64
|
-
onPlayRequest,
|
|
65
|
-
onPlay,
|
|
66
|
-
onPlaying,
|
|
67
|
-
onPause,
|
|
68
|
-
onStop,
|
|
69
|
-
onEnded,
|
|
70
|
-
onTimeUpdate,
|
|
71
|
-
onError,
|
|
72
|
-
onLoadedMetadata,
|
|
73
|
-
onFullscreenChange,
|
|
74
|
-
onWaiting,
|
|
75
|
-
onQualityChange,
|
|
76
|
-
onRateChange,
|
|
77
|
-
});
|
|
78
|
-
handlerRef.current = {
|
|
79
|
-
onPlayRequest,
|
|
80
|
-
onPlay,
|
|
81
|
-
onPlaying,
|
|
82
|
-
onPause,
|
|
83
|
-
onStop,
|
|
84
|
-
onEnded,
|
|
85
|
-
onTimeUpdate,
|
|
86
|
-
onError,
|
|
87
|
-
onLoadedMetadata,
|
|
88
|
-
onFullscreenChange,
|
|
89
|
-
onWaiting,
|
|
90
|
-
onQualityChange,
|
|
91
|
-
onRateChange,
|
|
92
|
-
};
|
|
93
|
-
const listenerMapRef = useRef<Record<string, EventListenerObject>>(
|
|
94
|
-
Object.fromEntries(
|
|
95
|
-
Object.entries(VIDEO_DOM_EVENT_MAP).map(([propKey, eventName]) => [
|
|
96
|
-
eventName,
|
|
97
|
-
{
|
|
98
|
-
handleEvent: (event: Event) => {
|
|
99
|
-
const handler = handlerRef.current[propKey as keyof typeof handlerRef.current];
|
|
100
|
-
if (typeof handler === "function") {
|
|
101
|
-
handler(event);
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
} satisfies EventListenerObject,
|
|
105
|
-
])
|
|
106
|
-
)
|
|
107
|
-
);
|
|
108
|
-
const elementRefCallback = useCallback((element: HTMLElement | null) => {
|
|
109
|
-
boundElementRef.current = bindElementEvents(boundElementRef.current, element, listenerMapRef.current);
|
|
110
|
-
elementRef.current = element;
|
|
111
|
-
assignForwardedRef(ref, element);
|
|
112
|
-
}, [ref]);
|
|
113
|
-
|
|
114
|
-
useEffect(() => () => {
|
|
115
|
-
unbindElementEvents(boundElementRef.current, listenerMapRef.current);
|
|
116
|
-
boundElementRef.current = null;
|
|
117
|
-
elementRef.current = null;
|
|
118
|
-
}, []);
|
|
119
|
-
|
|
120
|
-
useEffect(() => {
|
|
121
|
-
const el = elementRef.current;
|
|
122
|
-
if (!el) return;
|
|
123
|
-
if (rotate === undefined || rotate === null) {
|
|
124
|
-
el.removeAttribute("rotate");
|
|
125
|
-
} else {
|
|
126
|
-
el.setAttribute("rotate", String(rotate).trim());
|
|
127
|
-
}
|
|
128
|
-
if (objectFit === undefined || objectFit === null) {
|
|
129
|
-
el.removeAttribute("object-fit");
|
|
130
|
-
} else {
|
|
131
|
-
el.setAttribute("object-fit", String(objectFit).trim().toLowerCase());
|
|
132
|
-
}
|
|
133
|
-
}, [rotate, objectFit]);
|
|
134
|
-
|
|
135
|
-
// Set pageBindings property on custom element
|
|
136
|
-
useEffect(() => {
|
|
137
|
-
const el = elementRef.current as any;
|
|
138
|
-
if (el && pageBindings) {
|
|
139
|
-
el.pageBindings = pageBindings;
|
|
140
|
-
}
|
|
141
|
-
}, [pageBindings]);
|
|
142
|
-
|
|
143
|
-
const domProps = buildVideoNativeAttrs({
|
|
144
|
-
id: resolvedId,
|
|
145
|
-
src,
|
|
146
|
-
poster,
|
|
147
|
-
autoplay,
|
|
148
|
-
loop,
|
|
149
|
-
muted,
|
|
150
|
-
controls,
|
|
151
|
-
progressBar,
|
|
152
|
-
live,
|
|
153
|
-
volume,
|
|
154
|
-
qualities,
|
|
155
|
-
playbackRates,
|
|
156
|
-
}, rest as Record<string, unknown>);
|
|
157
|
-
|
|
158
|
-
return React.createElement('lx-video', {
|
|
159
|
-
ref: elementRefCallback,
|
|
160
|
-
className,
|
|
161
|
-
style,
|
|
162
|
-
...domProps
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
LxVideo.displayName = 'LxVideo';
|
package/src/react/hook.ts
DELETED
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import type {
|
|
3
|
-
LxChannel,
|
|
4
|
-
LxBridgeError,
|
|
5
|
-
LxStream,
|
|
6
|
-
} from "@lingxia/bridge";
|
|
7
|
-
import {
|
|
8
|
-
ensurePageBridgeSubscription,
|
|
9
|
-
getMethodKey,
|
|
10
|
-
getPageActions,
|
|
11
|
-
getPageSnapshot,
|
|
12
|
-
invokeMethod,
|
|
13
|
-
resolveParams,
|
|
14
|
-
stableParamKey,
|
|
15
|
-
subscribePageSnapshot,
|
|
16
|
-
toBridgeError,
|
|
17
|
-
type ActionMap,
|
|
18
|
-
type ChannelIn,
|
|
19
|
-
type ChannelOut,
|
|
20
|
-
type Listener,
|
|
21
|
-
type MethodParams,
|
|
22
|
-
type ParamsSource,
|
|
23
|
-
type Snapshot,
|
|
24
|
-
type StreamData,
|
|
25
|
-
type StreamResult,
|
|
26
|
-
} from "../shared/runtime.js";
|
|
27
|
-
|
|
28
|
-
export function useLxPage<
|
|
29
|
-
TData = Snapshot,
|
|
30
|
-
TActions extends ActionMap = ActionMap,
|
|
31
|
-
>(): { data: TData; actions: TActions } {
|
|
32
|
-
ensurePageBridgeSubscription();
|
|
33
|
-
const [, setVersion] = React.useState(0);
|
|
34
|
-
|
|
35
|
-
React.useEffect(() => {
|
|
36
|
-
ensurePageBridgeSubscription();
|
|
37
|
-
const listener: Listener = () => setVersion((v) => v + 1);
|
|
38
|
-
const unsubscribe = subscribePageSnapshot(listener);
|
|
39
|
-
setVersion((v) => v + 1);
|
|
40
|
-
return unsubscribe;
|
|
41
|
-
}, []);
|
|
42
|
-
|
|
43
|
-
const actions = React.useMemo(() => getPageActions<TActions>(), []);
|
|
44
|
-
return { data: getPageSnapshot<TData>(), actions };
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface LxStreamOptions<TData, TReduced> {
|
|
48
|
-
params?: unknown | (() => unknown);
|
|
49
|
-
manual?: boolean;
|
|
50
|
-
reduce?: (accumulated: TReduced, chunk: TData) => TReduced;
|
|
51
|
-
initial?: TReduced;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export interface LxStreamState<TData, TResult = unknown> {
|
|
55
|
-
data: TData | undefined;
|
|
56
|
-
result: TResult | undefined;
|
|
57
|
-
error: LxBridgeError | undefined;
|
|
58
|
-
streaming: boolean;
|
|
59
|
-
cancel: () => void;
|
|
60
|
-
start: () => void;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function useLxStream<
|
|
64
|
-
TMethod extends (...args: any[]) => LxStream<any, any>,
|
|
65
|
-
TReduced = StreamData<TMethod>,
|
|
66
|
-
>(
|
|
67
|
-
method: TMethod,
|
|
68
|
-
options?: LxStreamOptions<StreamData<TMethod>, TReduced> & {
|
|
69
|
-
params?: ParamsSource<MethodParams<TMethod>>;
|
|
70
|
-
},
|
|
71
|
-
): LxStreamState<
|
|
72
|
-
TReduced extends StreamData<TMethod> ? StreamData<TMethod> : TReduced,
|
|
73
|
-
StreamResult<TMethod>
|
|
74
|
-
> {
|
|
75
|
-
type TData = StreamData<TMethod>;
|
|
76
|
-
type TResult = StreamResult<TMethod>;
|
|
77
|
-
type TOut = TReduced extends TData ? TData : TReduced;
|
|
78
|
-
|
|
79
|
-
const [state, setState] = React.useState<{
|
|
80
|
-
data: TOut | undefined;
|
|
81
|
-
result: TResult | undefined;
|
|
82
|
-
error: LxBridgeError | undefined;
|
|
83
|
-
streaming: boolean;
|
|
84
|
-
}>({
|
|
85
|
-
data: (options?.reduce ? options.initial : undefined) as TOut | undefined,
|
|
86
|
-
result: undefined,
|
|
87
|
-
error: undefined,
|
|
88
|
-
streaming: false,
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
const handleRef = React.useRef<LxStream<TData, TResult> | null>(null);
|
|
92
|
-
const accRef = React.useRef<TReduced | undefined>(options?.initial);
|
|
93
|
-
const optionsRef = React.useRef(options);
|
|
94
|
-
const methodRef = React.useRef(method);
|
|
95
|
-
const paramsRef = React.useRef(resolveParams(options?.params));
|
|
96
|
-
const runIdRef = React.useRef(0);
|
|
97
|
-
const resolvedParams = resolveParams(options?.params);
|
|
98
|
-
const paramsKey = options?.manual ? "" : stableParamKey(resolvedParams);
|
|
99
|
-
const methodDep = getMethodKey(method) ?? method;
|
|
100
|
-
|
|
101
|
-
optionsRef.current = options;
|
|
102
|
-
methodRef.current = method;
|
|
103
|
-
paramsRef.current = resolvedParams;
|
|
104
|
-
|
|
105
|
-
const cancel = React.useCallback(() => {
|
|
106
|
-
runIdRef.current += 1;
|
|
107
|
-
handleRef.current?.cancel();
|
|
108
|
-
handleRef.current = null;
|
|
109
|
-
setState((prev) => ({ ...prev, streaming: false }));
|
|
110
|
-
}, []);
|
|
111
|
-
|
|
112
|
-
const start = React.useCallback(() => {
|
|
113
|
-
handleRef.current?.cancel();
|
|
114
|
-
const runId = runIdRef.current + 1;
|
|
115
|
-
runIdRef.current = runId;
|
|
116
|
-
|
|
117
|
-
const opts = optionsRef.current;
|
|
118
|
-
accRef.current = opts?.initial;
|
|
119
|
-
setState({
|
|
120
|
-
data: (opts?.reduce ? opts.initial : undefined) as TOut | undefined,
|
|
121
|
-
result: undefined,
|
|
122
|
-
error: undefined,
|
|
123
|
-
streaming: true,
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
let handle: LxStream<TData, TResult>;
|
|
127
|
-
try {
|
|
128
|
-
handle = invokeMethod(methodRef.current, paramsRef.current) as LxStream<TData, TResult>;
|
|
129
|
-
} catch (err: unknown) {
|
|
130
|
-
if (runIdRef.current !== runId) return;
|
|
131
|
-
handleRef.current = null;
|
|
132
|
-
setState((prev) => ({
|
|
133
|
-
...prev,
|
|
134
|
-
error: toBridgeError(err),
|
|
135
|
-
streaming: false,
|
|
136
|
-
}));
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
handleRef.current = handle;
|
|
140
|
-
|
|
141
|
-
handle.on("data", (chunk: TData) => {
|
|
142
|
-
if (runIdRef.current !== runId) return;
|
|
143
|
-
const currentOpts = optionsRef.current;
|
|
144
|
-
if (currentOpts?.reduce) {
|
|
145
|
-
accRef.current = currentOpts.reduce(
|
|
146
|
-
accRef.current as TReduced,
|
|
147
|
-
chunk,
|
|
148
|
-
);
|
|
149
|
-
setState((prev) => ({
|
|
150
|
-
...prev,
|
|
151
|
-
data: accRef.current as TOut,
|
|
152
|
-
}));
|
|
153
|
-
} else {
|
|
154
|
-
setState((prev) => ({
|
|
155
|
-
...prev,
|
|
156
|
-
data: chunk as unknown as TOut,
|
|
157
|
-
}));
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
handle.on("end", (result: TResult) => {
|
|
162
|
-
if (runIdRef.current !== runId) return;
|
|
163
|
-
handleRef.current = null;
|
|
164
|
-
setState((prev) => ({
|
|
165
|
-
...prev,
|
|
166
|
-
result,
|
|
167
|
-
streaming: false,
|
|
168
|
-
}));
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
handle.on("error", (err: LxBridgeError) => {
|
|
172
|
-
if (runIdRef.current !== runId) return;
|
|
173
|
-
handleRef.current = null;
|
|
174
|
-
setState((prev) => ({
|
|
175
|
-
...prev,
|
|
176
|
-
error: err,
|
|
177
|
-
streaming: false,
|
|
178
|
-
}));
|
|
179
|
-
});
|
|
180
|
-
}, []);
|
|
181
|
-
|
|
182
|
-
React.useEffect(() => {
|
|
183
|
-
if (!options?.manual) {
|
|
184
|
-
start();
|
|
185
|
-
}
|
|
186
|
-
return () => {
|
|
187
|
-
runIdRef.current += 1;
|
|
188
|
-
handleRef.current?.cancel();
|
|
189
|
-
handleRef.current = null;
|
|
190
|
-
};
|
|
191
|
-
}, [methodDep, options?.manual, paramsKey, start]);
|
|
192
|
-
|
|
193
|
-
return { ...state, cancel, start };
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export interface LxChannelOptions {
|
|
197
|
-
params?: unknown | (() => unknown);
|
|
198
|
-
manual?: boolean;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export interface LxChannelState<TData, TOut = TData> {
|
|
202
|
-
last: TData | undefined;
|
|
203
|
-
error: LxBridgeError | undefined;
|
|
204
|
-
connecting: boolean;
|
|
205
|
-
connected: boolean;
|
|
206
|
-
send: (payload: TOut) => void;
|
|
207
|
-
close: (code?: string, reason?: string) => void;
|
|
208
|
-
reopen: () => void;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
export function useLxChannel<
|
|
212
|
-
TMethod extends (...args: any[]) => Promise<LxChannel<any, any>>,
|
|
213
|
-
>(
|
|
214
|
-
method: TMethod,
|
|
215
|
-
options?: LxChannelOptions & {
|
|
216
|
-
params?: ParamsSource<MethodParams<TMethod>>;
|
|
217
|
-
},
|
|
218
|
-
): LxChannelState<ChannelIn<TMethod>, ChannelOut<TMethod>> {
|
|
219
|
-
type TIn = ChannelIn<TMethod>;
|
|
220
|
-
type TOut = ChannelOut<TMethod>;
|
|
221
|
-
|
|
222
|
-
const [state, setState] = React.useState<{
|
|
223
|
-
last: TIn | undefined;
|
|
224
|
-
error: LxBridgeError | undefined;
|
|
225
|
-
connecting: boolean;
|
|
226
|
-
connected: boolean;
|
|
227
|
-
}>({
|
|
228
|
-
last: undefined,
|
|
229
|
-
error: undefined,
|
|
230
|
-
connecting: false,
|
|
231
|
-
connected: false,
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
const chRef = React.useRef<LxChannel<TIn, TOut> | null>(null);
|
|
235
|
-
const methodRef = React.useRef(method);
|
|
236
|
-
const paramsRef = React.useRef(resolveParams(options?.params));
|
|
237
|
-
const runIdRef = React.useRef(0);
|
|
238
|
-
const resolvedParams = resolveParams(options?.params);
|
|
239
|
-
const paramsKey = options?.manual ? "" : stableParamKey(resolvedParams);
|
|
240
|
-
const methodDep = getMethodKey(method) ?? method;
|
|
241
|
-
|
|
242
|
-
methodRef.current = method;
|
|
243
|
-
paramsRef.current = resolvedParams;
|
|
244
|
-
|
|
245
|
-
const send = React.useCallback((payload: TOut) => {
|
|
246
|
-
chRef.current?.send(payload);
|
|
247
|
-
}, []);
|
|
248
|
-
|
|
249
|
-
const close = React.useCallback((code?: string, reason?: string) => {
|
|
250
|
-
runIdRef.current += 1;
|
|
251
|
-
chRef.current?.close(code, reason);
|
|
252
|
-
chRef.current = null;
|
|
253
|
-
setState((prev) => ({ ...prev, connecting: false, connected: false }));
|
|
254
|
-
}, []);
|
|
255
|
-
|
|
256
|
-
const reopen = React.useCallback(() => {
|
|
257
|
-
chRef.current?.close();
|
|
258
|
-
chRef.current = null;
|
|
259
|
-
|
|
260
|
-
const runId = ++runIdRef.current;
|
|
261
|
-
setState({
|
|
262
|
-
last: undefined,
|
|
263
|
-
error: undefined,
|
|
264
|
-
connecting: true,
|
|
265
|
-
connected: false,
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
Promise.resolve(
|
|
269
|
-
invokeMethod(methodRef.current, paramsRef.current) as Promise<LxChannel<TIn, TOut>>,
|
|
270
|
-
)
|
|
271
|
-
.then((ch) => {
|
|
272
|
-
if (runIdRef.current !== runId) {
|
|
273
|
-
ch.close();
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
chRef.current = ch;
|
|
277
|
-
setState((prev) => ({ ...prev, connecting: false, connected: true }));
|
|
278
|
-
|
|
279
|
-
ch.on("data", (payload) => {
|
|
280
|
-
if (runIdRef.current !== runId) return;
|
|
281
|
-
setState((prev) => ({ ...prev, last: payload as TIn }));
|
|
282
|
-
});
|
|
283
|
-
ch.on("close", () => {
|
|
284
|
-
if (runIdRef.current !== runId) return;
|
|
285
|
-
chRef.current = null;
|
|
286
|
-
setState((prev) => ({ ...prev, connecting: false, connected: false }));
|
|
287
|
-
});
|
|
288
|
-
ch.on("error", (err: LxBridgeError) => {
|
|
289
|
-
if (runIdRef.current !== runId) return;
|
|
290
|
-
chRef.current = null;
|
|
291
|
-
setState((prev) => ({ ...prev, error: err, connecting: false, connected: false }));
|
|
292
|
-
});
|
|
293
|
-
})
|
|
294
|
-
.catch((err: unknown) => {
|
|
295
|
-
if (runIdRef.current !== runId) return;
|
|
296
|
-
setState({
|
|
297
|
-
last: undefined,
|
|
298
|
-
error: toBridgeError(err),
|
|
299
|
-
connecting: false,
|
|
300
|
-
connected: false,
|
|
301
|
-
});
|
|
302
|
-
});
|
|
303
|
-
}, []);
|
|
304
|
-
|
|
305
|
-
React.useEffect(() => {
|
|
306
|
-
if (!options?.manual) {
|
|
307
|
-
reopen();
|
|
308
|
-
}
|
|
309
|
-
return () => {
|
|
310
|
-
runIdRef.current += 1;
|
|
311
|
-
chRef.current?.close();
|
|
312
|
-
chRef.current = null;
|
|
313
|
-
};
|
|
314
|
-
}, [methodDep, options?.manual, paramsKey, reopen]);
|
|
315
|
-
|
|
316
|
-
return { ...state, send, close, reopen };
|
|
317
|
-
}
|
package/src/react/index.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export {
|
|
2
|
-
useLxPage,
|
|
3
|
-
useLxStream,
|
|
4
|
-
useLxChannel,
|
|
5
|
-
type LxStreamOptions,
|
|
6
|
-
type LxStreamState,
|
|
7
|
-
type LxChannelOptions,
|
|
8
|
-
type LxChannelState,
|
|
9
|
-
} from "./hook.js";
|
|
10
|
-
export { LxVideo, type LxVideoProps } from "./LxVideo.js";
|
|
11
|
-
export { LxPicker, type LxPickerProps } from "./LxPicker.js";
|
|
12
|
-
export { LxNavigator, type LxNavigatorProps } from "./LxNavigator.js";
|
|
13
|
-
export { LxInput, type LxInputProps } from "./LxInput.js";
|
|
14
|
-
export { LxTextarea, type LxTextareaProps } from "./LxTextarea.js";
|