@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
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { ForwardedRef } from "react";
|
|
2
|
-
|
|
3
|
-
export function getCustomEventDetail<T>(event: Event): T {
|
|
4
|
-
return ((event as CustomEvent).detail ?? {}) as T;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function assignForwardedRef<T>(ref: ForwardedRef<T>, value: T | null): void {
|
|
8
|
-
if (typeof ref === "function") {
|
|
9
|
-
ref(value);
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
if (ref) {
|
|
13
|
-
ref.current = value;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function bindElementEvents(
|
|
18
|
-
boundElement: HTMLElement | null,
|
|
19
|
-
nextElement: HTMLElement | null,
|
|
20
|
-
listeners: Record<string, EventListenerObject>
|
|
21
|
-
): HTMLElement | null {
|
|
22
|
-
if (boundElement && boundElement !== nextElement) {
|
|
23
|
-
unbindElementEvents(boundElement, listeners);
|
|
24
|
-
boundElement = null;
|
|
25
|
-
}
|
|
26
|
-
if (nextElement && boundElement !== nextElement) {
|
|
27
|
-
for (const [event, listener] of Object.entries(listeners)) {
|
|
28
|
-
nextElement.addEventListener(event, listener);
|
|
29
|
-
}
|
|
30
|
-
boundElement = nextElement;
|
|
31
|
-
}
|
|
32
|
-
return boundElement;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function unbindElementEvents(
|
|
36
|
-
boundElement: HTMLElement | null,
|
|
37
|
-
listeners: Record<string, EventListenerObject>
|
|
38
|
-
): void {
|
|
39
|
-
if (!boundElement) return;
|
|
40
|
-
for (const [event, listener] of Object.entries(listeners)) {
|
|
41
|
-
boundElement.removeEventListener(event, listener);
|
|
42
|
-
}
|
|
43
|
-
}
|
package/src/shared/runtime.ts
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
DataSubscriber,
|
|
3
|
-
LxBridgeError,
|
|
4
|
-
LxChannel,
|
|
5
|
-
LxStream,
|
|
6
|
-
StateInfo,
|
|
7
|
-
} from "@lingxia/bridge";
|
|
8
|
-
|
|
9
|
-
export type ActionMap = Record<string, (...args: unknown[]) => unknown>;
|
|
10
|
-
export type Snapshot = Record<string, unknown>;
|
|
11
|
-
export type Listener = () => void;
|
|
12
|
-
export type ParamsSource<T> = T | (() => T);
|
|
13
|
-
export type MethodParams<TMethod> = TMethod extends () => any
|
|
14
|
-
? undefined
|
|
15
|
-
: TMethod extends (params: infer P) => any
|
|
16
|
-
? P
|
|
17
|
-
: never;
|
|
18
|
-
export type StreamData<TMethod> =
|
|
19
|
-
TMethod extends (...args: any[]) => LxStream<infer TData, any> ? TData : never;
|
|
20
|
-
export type StreamResult<TMethod> =
|
|
21
|
-
TMethod extends (...args: any[]) => LxStream<any, infer TResult>
|
|
22
|
-
? TResult
|
|
23
|
-
: never;
|
|
24
|
-
export type ChannelIn<TMethod> =
|
|
25
|
-
TMethod extends (...args: any[]) => Promise<LxChannel<infer TIn, any>>
|
|
26
|
-
? TIn
|
|
27
|
-
: never;
|
|
28
|
-
export type ChannelOut<TMethod> =
|
|
29
|
-
TMethod extends (...args: any[]) => Promise<LxChannel<any, infer TOut>>
|
|
30
|
-
? TOut
|
|
31
|
-
: never;
|
|
32
|
-
|
|
33
|
-
let snapshot: Snapshot = {};
|
|
34
|
-
let stateInfo: StateInfo = { rev: -1, initial: true };
|
|
35
|
-
let subscribed = false;
|
|
36
|
-
let subscribeRetryTimer: ReturnType<typeof setTimeout> | null = null;
|
|
37
|
-
let initialSnapshotResolved = false;
|
|
38
|
-
let snapshotRequestInFlight = false;
|
|
39
|
-
const listeners = new Set<Listener>();
|
|
40
|
-
|
|
41
|
-
export function toBridgeError(err: unknown): LxBridgeError {
|
|
42
|
-
return err && typeof err === "object" && "code" in err
|
|
43
|
-
? (err as LxBridgeError)
|
|
44
|
-
: {
|
|
45
|
-
code: "BRIDGE_INTERNAL_ERROR",
|
|
46
|
-
message: err instanceof Error ? err.message : String(err),
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function resolveParams<T>(source?: ParamsSource<T>): T | undefined {
|
|
51
|
-
if (typeof source === "function") {
|
|
52
|
-
return (source as () => T)();
|
|
53
|
-
}
|
|
54
|
-
return source;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function stableParamKey(value: unknown): string {
|
|
58
|
-
if (value === undefined) return "undefined";
|
|
59
|
-
try {
|
|
60
|
-
return JSON.stringify(value) ?? "undefined";
|
|
61
|
-
} catch {
|
|
62
|
-
return String(value);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function invokeMethod<TMethod extends (...args: any[]) => any>(
|
|
67
|
-
method: TMethod,
|
|
68
|
-
params: unknown,
|
|
69
|
-
): ReturnType<TMethod> {
|
|
70
|
-
if (params === undefined) {
|
|
71
|
-
return method() as ReturnType<TMethod>;
|
|
72
|
-
}
|
|
73
|
-
return method(params) as ReturnType<TMethod>;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function getMethodKey(method: unknown): string | undefined {
|
|
77
|
-
if (typeof method !== "function") return undefined;
|
|
78
|
-
const candidate = (method as { __funcName?: unknown }).__funcName;
|
|
79
|
-
return typeof candidate === "string" && candidate !== "" ? candidate : undefined;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function notifyListeners(): void {
|
|
83
|
-
listeners.forEach((listener) => {
|
|
84
|
-
try {
|
|
85
|
-
listener();
|
|
86
|
-
} catch {
|
|
87
|
-
// Ignore listener errors to avoid breaking state fanout.
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function updateSnapshot(next: unknown, info: StateInfo): void {
|
|
93
|
-
snapshot = next && typeof next === "object" ? (next as Snapshot) : {};
|
|
94
|
-
stateInfo = info;
|
|
95
|
-
notifyListeners();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function scheduleSubscribeRetry(): void {
|
|
99
|
-
if (subscribeRetryTimer !== null || subscribed) return;
|
|
100
|
-
subscribeRetryTimer = setTimeout(() => {
|
|
101
|
-
subscribeRetryTimer = null;
|
|
102
|
-
ensurePageBridgeSubscription();
|
|
103
|
-
}, 10);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function requestInitialSnapshot(bridge: Window["LingXiaBridge"] | undefined): void {
|
|
107
|
-
if (initialSnapshotResolved || snapshotRequestInFlight) return;
|
|
108
|
-
if (!bridge?.call) return;
|
|
109
|
-
snapshotRequestInFlight = true;
|
|
110
|
-
bridge
|
|
111
|
-
.call("state.getSnapshot", { scope: "page" })
|
|
112
|
-
.then(() => {
|
|
113
|
-
initialSnapshotResolved = true;
|
|
114
|
-
})
|
|
115
|
-
.catch(() => {
|
|
116
|
-
scheduleSubscribeRetry();
|
|
117
|
-
})
|
|
118
|
-
.finally(() => {
|
|
119
|
-
snapshotRequestInFlight = false;
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export function ensurePageBridgeSubscription(): void {
|
|
124
|
-
if (subscribed) return;
|
|
125
|
-
const bridge = window.LingXiaBridge;
|
|
126
|
-
const subscribeState = bridge?.state?.subscribe;
|
|
127
|
-
if (!subscribeState) {
|
|
128
|
-
scheduleSubscribeRetry();
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
subscribeState((next, info) => {
|
|
132
|
-
updateSnapshot(next, info);
|
|
133
|
-
});
|
|
134
|
-
subscribed = true;
|
|
135
|
-
requestInitialSnapshot(bridge);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export function subscribePageSnapshot(listener: Listener): () => void {
|
|
139
|
-
ensurePageBridgeSubscription();
|
|
140
|
-
listeners.add(listener);
|
|
141
|
-
return () => {
|
|
142
|
-
listeners.delete(listener);
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export function subscribePageData(
|
|
147
|
-
callback: DataSubscriber,
|
|
148
|
-
): () => void {
|
|
149
|
-
if (typeof callback !== "function") return () => {};
|
|
150
|
-
ensurePageBridgeSubscription();
|
|
151
|
-
|
|
152
|
-
if (stateInfo.rev >= 0) {
|
|
153
|
-
callback(snapshot, { rev: stateInfo.rev, initial: true });
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return subscribePageSnapshot(() => {
|
|
157
|
-
callback(snapshot, stateInfo);
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export function getPageSnapshot<TData = Snapshot>(): TData {
|
|
162
|
-
ensurePageBridgeSubscription();
|
|
163
|
-
return snapshot as TData;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export function getPageActions<TActions extends ActionMap>(): TActions {
|
|
167
|
-
const actions: ActionMap = {};
|
|
168
|
-
const bridge = window.__pageBridge;
|
|
169
|
-
if (!bridge?.__names) {
|
|
170
|
-
return actions as TActions;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
for (const name of bridge.__names) {
|
|
174
|
-
if (typeof name !== "string") continue;
|
|
175
|
-
const fn = bridge[name];
|
|
176
|
-
if (typeof fn === "function") {
|
|
177
|
-
actions[name] = fn as (...args: unknown[]) => unknown;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return actions as TActions;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export function getPageStateInfo(): StateInfo {
|
|
185
|
-
return stateInfo;
|
|
186
|
-
}
|
package/src/vue/LxInput.vue
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed, h, onBeforeUnmount, ref, useAttrs, watch } from 'vue';
|
|
3
|
-
import { registerInputComponent } from '@lingxia/elements';
|
|
4
|
-
import { buildInputNativeAttrs } from '@lingxia/elements';
|
|
5
|
-
import type { LxInputProps } from './types.js';
|
|
6
|
-
import {
|
|
7
|
-
bindElementEvents,
|
|
8
|
-
getCustomEventDetail,
|
|
9
|
-
unbindElementEvents,
|
|
10
|
-
} from './text_component_shared.js';
|
|
11
|
-
|
|
12
|
-
const props = withDefaults(defineProps<LxInputProps>(), {
|
|
13
|
-
type: 'text',
|
|
14
|
-
disabled: false,
|
|
15
|
-
confirmType: 'done',
|
|
16
|
-
});
|
|
17
|
-
const attrs = useAttrs();
|
|
18
|
-
|
|
19
|
-
const emit = defineEmits<{
|
|
20
|
-
'update:modelValue': [value: string];
|
|
21
|
-
input: [detail: Record<string, unknown>];
|
|
22
|
-
change: [detail: Record<string, unknown>];
|
|
23
|
-
focus: [detail: Record<string, unknown>];
|
|
24
|
-
blur: [detail: Record<string, unknown>];
|
|
25
|
-
confirm: [detail: Record<string, unknown>];
|
|
26
|
-
keyboardHeightChange: [detail: Record<string, unknown>];
|
|
27
|
-
nicknameReview: [detail: Record<string, unknown>];
|
|
28
|
-
}>();
|
|
29
|
-
|
|
30
|
-
if (typeof window !== 'undefined') {
|
|
31
|
-
registerInputComponent();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const elementRef = ref<HTMLElement | null>(null);
|
|
35
|
-
let boundElement: HTMLElement | null = null;
|
|
36
|
-
|
|
37
|
-
const inputEventListeners: Record<string, EventListenerObject> = {
|
|
38
|
-
input: {
|
|
39
|
-
handleEvent: (event: Event) => {
|
|
40
|
-
const detail = getCustomEventDetail<Record<string, unknown>>(event);
|
|
41
|
-
if (typeof detail.value === 'string') {
|
|
42
|
-
emit('update:modelValue', detail.value);
|
|
43
|
-
}
|
|
44
|
-
emit('input', detail);
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
change: {
|
|
48
|
-
handleEvent: (event: Event) => emit('change', getCustomEventDetail<Record<string, unknown>>(event)),
|
|
49
|
-
},
|
|
50
|
-
focus: {
|
|
51
|
-
handleEvent: (event: Event) => emit('focus', getCustomEventDetail<Record<string, unknown>>(event)),
|
|
52
|
-
},
|
|
53
|
-
blur: {
|
|
54
|
-
handleEvent: (event: Event) => emit('blur', getCustomEventDetail<Record<string, unknown>>(event)),
|
|
55
|
-
},
|
|
56
|
-
confirm: {
|
|
57
|
-
handleEvent: (event: Event) => emit('confirm', getCustomEventDetail<Record<string, unknown>>(event)),
|
|
58
|
-
},
|
|
59
|
-
keyboardheightchange: {
|
|
60
|
-
handleEvent: (event: Event) => emit('keyboardHeightChange', getCustomEventDetail<Record<string, unknown>>(event)),
|
|
61
|
-
},
|
|
62
|
-
nicknamereview: {
|
|
63
|
-
handleEvent: (event: Event) => emit('nicknameReview', getCustomEventDetail<Record<string, unknown>>(event)),
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
watch(elementRef, (element) => {
|
|
68
|
-
boundElement = bindElementEvents(boundElement, element, inputEventListeners);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
onBeforeUnmount(() => {
|
|
72
|
-
unbindElementEvents(boundElement, inputEventListeners);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
const inputProps = computed<Record<string, unknown>>(() => {
|
|
76
|
-
const result: Record<string, unknown> = buildInputNativeAttrs({
|
|
77
|
-
...props,
|
|
78
|
-
id: props.id ?? (typeof attrs.id === 'string' ? attrs.id : undefined),
|
|
79
|
-
}, attrs as Record<string, unknown>, elementRef.value !== null);
|
|
80
|
-
result.class = props.class ?? attrs.class;
|
|
81
|
-
result.style = props.style ?? attrs.style;
|
|
82
|
-
return result;
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
defineExpose({ el: elementRef });
|
|
86
|
-
|
|
87
|
-
const renderInput = () => h('lx-input', { ref: elementRef, ...inputProps.value });
|
|
88
|
-
</script>
|
|
89
|
-
|
|
90
|
-
<template>
|
|
91
|
-
<renderInput />
|
|
92
|
-
</template>
|
package/src/vue/LxNavigator.vue
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ref, h, onMounted, onBeforeUnmount, useAttrs } from 'vue';
|
|
3
|
-
import type { LxNavigatorEvent } from '@lingxia/elements';
|
|
4
|
-
import { buildNavigatorNativeAttrs } from '@lingxia/elements';
|
|
5
|
-
import type { LxNavigatorProps } from './types.js';
|
|
6
|
-
import '@lingxia/elements';
|
|
7
|
-
|
|
8
|
-
const props = withDefaults(defineProps<LxNavigatorProps>(), {
|
|
9
|
-
openType: 'navigate',
|
|
10
|
-
delta: 1,
|
|
11
|
-
hoverClass: 'navigator-hover',
|
|
12
|
-
hoverStopPropagation: false,
|
|
13
|
-
hoverStartTime: 20,
|
|
14
|
-
hoverStayTime: 70,
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
const slots = defineSlots();
|
|
18
|
-
const attrs = useAttrs();
|
|
19
|
-
|
|
20
|
-
const emit = defineEmits<{
|
|
21
|
-
success: [e: LxNavigatorEvent];
|
|
22
|
-
fail: [e: LxNavigatorEvent];
|
|
23
|
-
complete: [e: LxNavigatorEvent];
|
|
24
|
-
}>();
|
|
25
|
-
|
|
26
|
-
const elementRef = ref<HTMLElement | null>(null);
|
|
27
|
-
|
|
28
|
-
const handleSuccess = (e: Event) => emit('success', e as LxNavigatorEvent);
|
|
29
|
-
const handleFail = (e: Event) => emit('fail', e as LxNavigatorEvent);
|
|
30
|
-
const handleComplete = (e: Event) => emit('complete', e as LxNavigatorEvent);
|
|
31
|
-
const successListener: EventListenerObject = { handleEvent: handleSuccess };
|
|
32
|
-
const failListener: EventListenerObject = { handleEvent: handleFail };
|
|
33
|
-
const completeListener: EventListenerObject = { handleEvent: handleComplete };
|
|
34
|
-
|
|
35
|
-
onMounted(() => {
|
|
36
|
-
const el = elementRef.value;
|
|
37
|
-
if (!el) return;
|
|
38
|
-
el.addEventListener('success', successListener);
|
|
39
|
-
el.addEventListener('fail', failListener);
|
|
40
|
-
el.addEventListener('complete', completeListener);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
onBeforeUnmount(() => {
|
|
44
|
-
const el = elementRef.value;
|
|
45
|
-
if (!el) return;
|
|
46
|
-
el.removeEventListener('success', successListener);
|
|
47
|
-
el.removeEventListener('fail', failListener);
|
|
48
|
-
el.removeEventListener('complete', completeListener);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
defineExpose({ el: elementRef });
|
|
52
|
-
|
|
53
|
-
const render = () => h(
|
|
54
|
-
'lx-navigator',
|
|
55
|
-
{
|
|
56
|
-
ref: elementRef,
|
|
57
|
-
...buildNavigatorNativeAttrs({
|
|
58
|
-
url: props.url,
|
|
59
|
-
openType: props.openType,
|
|
60
|
-
target: props.target,
|
|
61
|
-
delta: props.delta,
|
|
62
|
-
appId: props.appId,
|
|
63
|
-
path: props.path,
|
|
64
|
-
phoneNumber: props.phoneNumber,
|
|
65
|
-
hoverClass: props.hoverClass,
|
|
66
|
-
hoverStopPropagation: props.hoverStopPropagation,
|
|
67
|
-
hoverStartTime: props.hoverStartTime,
|
|
68
|
-
hoverStayTime: props.hoverStayTime,
|
|
69
|
-
}, attrs as Record<string, unknown>),
|
|
70
|
-
class: props.class ?? attrs.class,
|
|
71
|
-
style: props.style ?? attrs.style,
|
|
72
|
-
},
|
|
73
|
-
slots.default?.()
|
|
74
|
-
);
|
|
75
|
-
</script>
|
|
76
|
-
|
|
77
|
-
<template>
|
|
78
|
-
<render />
|
|
79
|
-
</template>
|
package/src/vue/LxPicker.vue
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ref, computed, h, onBeforeUnmount, useAttrs, useId, watch } from 'vue';
|
|
3
|
-
import { registerPickerComponent } from '@lingxia/elements';
|
|
4
|
-
import {
|
|
5
|
-
buildPickerNativeAttrs,
|
|
6
|
-
getPickerDisplayText,
|
|
7
|
-
getPickerValueFromIndex,
|
|
8
|
-
} from '@lingxia/elements';
|
|
9
|
-
import { bindElementEvents, getCustomEventDetail, unbindElementEvents } from './text_component_shared.js';
|
|
10
|
-
import type { LxPickerProps } from './types.js';
|
|
11
|
-
|
|
12
|
-
const props = withDefaults(defineProps<LxPickerProps>(), {
|
|
13
|
-
placeholder: 'Please select',
|
|
14
|
-
disabled: false,
|
|
15
|
-
});
|
|
16
|
-
const attrs = useAttrs();
|
|
17
|
-
|
|
18
|
-
const slots = defineSlots();
|
|
19
|
-
|
|
20
|
-
const emit = defineEmits<{
|
|
21
|
-
'update:modelValue': [value: string | string[]];
|
|
22
|
-
confirm: [value: string | string[]];
|
|
23
|
-
cancel: [];
|
|
24
|
-
scroll: [value: string | string[]];
|
|
25
|
-
}>();
|
|
26
|
-
|
|
27
|
-
if (typeof window !== 'undefined') {
|
|
28
|
-
registerPickerComponent();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const visible = ref(false);
|
|
32
|
-
const vueId = useId();
|
|
33
|
-
const pickerId = computed(() => `lx-picker-${vueId.replace(/[:]/g, '')}`);
|
|
34
|
-
const pickerRef = ref<HTMLElement | null>(null);
|
|
35
|
-
let boundElement: HTMLElement | null = null;
|
|
36
|
-
const pickerEventListeners: Record<string, EventListenerObject> = {
|
|
37
|
-
change: {
|
|
38
|
-
handleEvent: (event: Event) => handleChange(event),
|
|
39
|
-
},
|
|
40
|
-
scroll: {
|
|
41
|
-
handleEvent: (event: Event) => handleScroll(event),
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const displayText = computed(() => getPickerDisplayText(props.modelValue, props.fields));
|
|
46
|
-
|
|
47
|
-
function handleChange(e: Event) {
|
|
48
|
-
props.onChange?.(e);
|
|
49
|
-
const detail = getCustomEventDetail<{
|
|
50
|
-
confirmed?: boolean;
|
|
51
|
-
cancelled?: boolean;
|
|
52
|
-
value?: string | string[];
|
|
53
|
-
index?: number | number[];
|
|
54
|
-
}>(e);
|
|
55
|
-
if (detail.confirmed) {
|
|
56
|
-
if (props.mode === 'date' || props.mode === 'time') {
|
|
57
|
-
const nextValue = detail.value ?? '';
|
|
58
|
-
emit('update:modelValue', nextValue);
|
|
59
|
-
emit('confirm', nextValue);
|
|
60
|
-
} else if (detail.index !== undefined) {
|
|
61
|
-
const nextValue = getPickerValueFromIndex(props.columns, detail.index);
|
|
62
|
-
emit('update:modelValue', nextValue);
|
|
63
|
-
emit('confirm', nextValue);
|
|
64
|
-
}
|
|
65
|
-
visible.value = false;
|
|
66
|
-
} else if (detail.cancelled) {
|
|
67
|
-
emit('cancel');
|
|
68
|
-
visible.value = false;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function handleScroll(e: Event) {
|
|
73
|
-
props.onNativeScroll?.(e);
|
|
74
|
-
const detail = getCustomEventDetail<{
|
|
75
|
-
value?: string | string[];
|
|
76
|
-
index?: number | number[];
|
|
77
|
-
}>(e);
|
|
78
|
-
if (detail.value !== undefined) {
|
|
79
|
-
emit('scroll', detail.value);
|
|
80
|
-
} else if (detail.index !== undefined) {
|
|
81
|
-
emit('scroll', getPickerValueFromIndex(props.columns, detail.index));
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function handleClick() {
|
|
86
|
-
if (!props.disabled) visible.value = true;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
watch(pickerRef, (element) => {
|
|
90
|
-
boundElement = bindElementEvents(boundElement, element, pickerEventListeners);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
onBeforeUnmount(() => {
|
|
94
|
-
unbindElementEvents(boundElement, pickerEventListeners);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
const pickerProps = computed(() => {
|
|
98
|
-
return buildPickerNativeAttrs({
|
|
99
|
-
id: pickerId.value,
|
|
100
|
-
columns: props.columns,
|
|
101
|
-
mode: props.mode,
|
|
102
|
-
start: props.start,
|
|
103
|
-
end: props.end,
|
|
104
|
-
fields: props.fields,
|
|
105
|
-
modelValue: props.modelValue,
|
|
106
|
-
cancelText: props.cancelText,
|
|
107
|
-
cancelTextColor: props.cancelTextColor,
|
|
108
|
-
cancelButtonColor: props.cancelButtonColor,
|
|
109
|
-
confirmText: props.confirmText,
|
|
110
|
-
confirmTextColor: props.confirmTextColor,
|
|
111
|
-
confirmButtonColor: props.confirmButtonColor,
|
|
112
|
-
}, attrs as Record<string, unknown>);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
const triggerStyle = computed(() => ({
|
|
116
|
-
display: 'flex',
|
|
117
|
-
alignItems: 'center',
|
|
118
|
-
justifyContent: 'space-between',
|
|
119
|
-
padding: '12px 14px',
|
|
120
|
-
backgroundColor: '#fff',
|
|
121
|
-
border: '1px solid #e5e7eb',
|
|
122
|
-
borderRadius: '8px',
|
|
123
|
-
cursor: props.disabled ? 'not-allowed' : 'pointer',
|
|
124
|
-
opacity: props.disabled ? 0.5 : 1,
|
|
125
|
-
width: '100%',
|
|
126
|
-
boxSizing: 'border-box',
|
|
127
|
-
}));
|
|
128
|
-
|
|
129
|
-
defineExpose({ el: pickerRef });
|
|
130
|
-
|
|
131
|
-
const renderPicker = () => visible.value ? h('lx-picker', { ref: pickerRef, ...pickerProps.value }) : null;
|
|
132
|
-
</script>
|
|
133
|
-
|
|
134
|
-
<template>
|
|
135
|
-
<slot :open="handleClick" :disabled="props.disabled">
|
|
136
|
-
<div :class="props.class ?? attrs.class" :style="[triggerStyle, props.style ?? attrs.style]" @click="handleClick">
|
|
137
|
-
<span :style="{ color: modelValue ? '#111' : '#9ca3af' }">{{ displayText || placeholder }}</span>
|
|
138
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#9ca3af" stroke-width="2">
|
|
139
|
-
<path d="M6 9l6 6 6-6" />
|
|
140
|
-
</svg>
|
|
141
|
-
</div>
|
|
142
|
-
</slot>
|
|
143
|
-
<renderPicker />
|
|
144
|
-
</template>
|
package/src/vue/LxTextarea.vue
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { computed, h, onBeforeUnmount, ref, useAttrs, watch } from 'vue';
|
|
3
|
-
import { registerTextareaComponent } from '@lingxia/elements';
|
|
4
|
-
import { buildTextareaNativeAttrs } from '@lingxia/elements';
|
|
5
|
-
import type { LxTextareaProps } from './types.js';
|
|
6
|
-
import {
|
|
7
|
-
bindElementEvents,
|
|
8
|
-
getCustomEventDetail,
|
|
9
|
-
unbindElementEvents,
|
|
10
|
-
} from './text_component_shared.js';
|
|
11
|
-
|
|
12
|
-
const props = withDefaults(defineProps<LxTextareaProps>(), {
|
|
13
|
-
disabled: false,
|
|
14
|
-
});
|
|
15
|
-
const attrs = useAttrs();
|
|
16
|
-
|
|
17
|
-
const emit = defineEmits<{
|
|
18
|
-
'update:modelValue': [value: string];
|
|
19
|
-
input: [detail: Record<string, unknown>];
|
|
20
|
-
change: [detail: Record<string, unknown>];
|
|
21
|
-
focus: [detail: Record<string, unknown>];
|
|
22
|
-
blur: [detail: Record<string, unknown>];
|
|
23
|
-
confirm: [detail: Record<string, unknown>];
|
|
24
|
-
lineChange: [detail: Record<string, unknown>];
|
|
25
|
-
keyboardHeightChange: [detail: Record<string, unknown>];
|
|
26
|
-
}>();
|
|
27
|
-
|
|
28
|
-
if (typeof window !== 'undefined') {
|
|
29
|
-
registerTextareaComponent();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const elementRef = ref<HTMLElement | null>(null);
|
|
33
|
-
let boundElement: HTMLElement | null = null;
|
|
34
|
-
|
|
35
|
-
const textareaEventListeners: Record<string, EventListenerObject> = {
|
|
36
|
-
input: {
|
|
37
|
-
handleEvent: (event: Event) => {
|
|
38
|
-
const detail = getCustomEventDetail<Record<string, unknown>>(event);
|
|
39
|
-
if (typeof detail.value === 'string') {
|
|
40
|
-
emit('update:modelValue', detail.value);
|
|
41
|
-
}
|
|
42
|
-
emit('input', detail);
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
change: {
|
|
46
|
-
handleEvent: (event: Event) => emit('change', getCustomEventDetail<Record<string, unknown>>(event)),
|
|
47
|
-
},
|
|
48
|
-
focus: {
|
|
49
|
-
handleEvent: (event: Event) => emit('focus', getCustomEventDetail<Record<string, unknown>>(event)),
|
|
50
|
-
},
|
|
51
|
-
blur: {
|
|
52
|
-
handleEvent: (event: Event) => emit('blur', getCustomEventDetail<Record<string, unknown>>(event)),
|
|
53
|
-
},
|
|
54
|
-
confirm: {
|
|
55
|
-
handleEvent: (event: Event) => emit('confirm', getCustomEventDetail<Record<string, unknown>>(event)),
|
|
56
|
-
},
|
|
57
|
-
linechange: {
|
|
58
|
-
handleEvent: (event: Event) => emit('lineChange', getCustomEventDetail<Record<string, unknown>>(event)),
|
|
59
|
-
},
|
|
60
|
-
keyboardheightchange: {
|
|
61
|
-
handleEvent: (event: Event) => emit('keyboardHeightChange', getCustomEventDetail<Record<string, unknown>>(event)),
|
|
62
|
-
},
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
watch(elementRef, (element) => {
|
|
66
|
-
boundElement = bindElementEvents(boundElement, element, textareaEventListeners);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
onBeforeUnmount(() => {
|
|
70
|
-
unbindElementEvents(boundElement, textareaEventListeners);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
const textareaProps = computed<Record<string, unknown>>(() => {
|
|
74
|
-
const result: Record<string, unknown> = buildTextareaNativeAttrs({
|
|
75
|
-
...props,
|
|
76
|
-
id: props.id ?? (typeof attrs.id === 'string' ? attrs.id : undefined),
|
|
77
|
-
}, attrs as Record<string, unknown>, elementRef.value !== null);
|
|
78
|
-
result.class = props.class ?? attrs.class;
|
|
79
|
-
result.style = props.style ?? attrs.style;
|
|
80
|
-
return result;
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
defineExpose({ el: elementRef });
|
|
84
|
-
|
|
85
|
-
const renderTextarea = () => h('lx-textarea', { ref: elementRef, ...textareaProps.value });
|
|
86
|
-
</script>
|
|
87
|
-
|
|
88
|
-
<template>
|
|
89
|
-
<renderTextarea />
|
|
90
|
-
</template>
|