@lingxia/elements 0.5.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.
Files changed (46) hide show
  1. package/dist/component.d.ts +50 -0
  2. package/dist/component.js +139 -0
  3. package/dist/dom.d.ts +10 -0
  4. package/dist/dom.js +70 -0
  5. package/dist/index.d.ts +9 -0
  6. package/dist/index.js +9 -0
  7. package/dist/input.d.ts +117 -0
  8. package/dist/input.js +699 -0
  9. package/dist/native_component_wrapper_shared.d.ts +74 -0
  10. package/dist/native_component_wrapper_shared.js +193 -0
  11. package/dist/nativecomponent.d.ts +6 -0
  12. package/dist/nativecomponent.js +82 -0
  13. package/dist/navigator.d.ts +83 -0
  14. package/dist/navigator.js +388 -0
  15. package/dist/picker-web.d.ts +2 -0
  16. package/dist/picker-web.js +727 -0
  17. package/dist/picker.d.ts +77 -0
  18. package/dist/picker.js +342 -0
  19. package/dist/platform.d.ts +6 -0
  20. package/dist/platform.js +24 -0
  21. package/dist/text_component_native_attrs.d.ts +53 -0
  22. package/dist/text_component_native_attrs.js +111 -0
  23. package/dist/text_component_shared.d.ts +7 -0
  24. package/dist/text_component_shared.js +148 -0
  25. package/dist/textarea.d.ts +129 -0
  26. package/dist/textarea.js +841 -0
  27. package/dist/types.d.ts +21 -0
  28. package/dist/types.js +1 -0
  29. package/dist/video.d.ts +134 -0
  30. package/dist/video.js +741 -0
  31. package/package.json +39 -0
  32. package/src/component.ts +164 -0
  33. package/src/dom.ts +83 -0
  34. package/src/index.ts +69 -0
  35. package/src/input.ts +799 -0
  36. package/src/native_component_wrapper_shared.ts +243 -0
  37. package/src/nativecomponent.ts +97 -0
  38. package/src/navigator.ts +533 -0
  39. package/src/picker-web.ts +719 -0
  40. package/src/picker.ts +418 -0
  41. package/src/platform.ts +25 -0
  42. package/src/text_component_native_attrs.ts +137 -0
  43. package/src/text_component_shared.ts +147 -0
  44. package/src/textarea.ts +959 -0
  45. package/src/types.ts +20 -0
  46. package/src/video.ts +855 -0
package/src/picker.ts ADDED
@@ -0,0 +1,418 @@
1
+ import {
2
+ sendNativeComponentMessage,
3
+ registerNativeComponentHandler,
4
+ addNativeComponentLayoutInvalidationListener
5
+ } from "./nativecomponent.js";
6
+ import { ensureComponentId } from "./component.js";
7
+ import { measureElement } from "./dom.js";
8
+ import { isAndroid, isHarmony, isDesktop } from "./platform.js";
9
+
10
+ const HARMONY_PROPS_PREFIX = "data:application/json,";
11
+
12
+ // Type definitions
13
+ export type LxPickerColumn = string[];
14
+ export type LxPickerCascadingColumns = [string[], Record<string, string[]>];
15
+ type LxPickerViewEventHandler = (e: LxPickerEvent) => void;
16
+
17
+ export interface LxPickerEventDetail {
18
+ index?: number | number[];
19
+ value?: string | string[];
20
+ confirmed?: boolean;
21
+ cancelled?: boolean;
22
+ }
23
+
24
+ export interface LxPickerEvent extends CustomEvent<LxPickerEventDetail> {
25
+ detail: LxPickerEventDetail;
26
+ }
27
+
28
+ export type LxPickerAttributes = {
29
+ id?: string;
30
+ mode?: 'selector' | 'multiSelector' | 'cascading' | 'date' | 'time';
31
+ columns?: LxPickerColumn[] | LxPickerCascadingColumns;
32
+ defaultIndex?: number | number[];
33
+ value?: string;
34
+ start?: string;
35
+ end?: string;
36
+ fields?: 'year' | 'month' | 'day' | 'range';
37
+ cancelText?: string;
38
+ confirmText?: string;
39
+ cancelButtonColor?: string;
40
+ confirmButtonColor?: string;
41
+ cancelTextColor?: string;
42
+ confirmTextColor?: string;
43
+ className?: string;
44
+ style?: any;
45
+ ref?: any;
46
+ onChange?: LxPickerViewEventHandler;
47
+ onScroll?: LxPickerViewEventHandler;
48
+ pageBindings?: Record<string, string>;
49
+ };
50
+
51
+ declare global {
52
+ namespace JSX {
53
+ interface IntrinsicElements {
54
+ "lx-picker": LxPickerAttributes;
55
+ }
56
+ }
57
+ }
58
+
59
+ // Component implementation
60
+ export class LxPickerElement extends HTMLElement {
61
+ static get observedAttributes() {
62
+ return [
63
+ "id",
64
+ "mode",
65
+ "columns",
66
+ "default-index",
67
+ "value",
68
+ "start",
69
+ "end",
70
+ "fields",
71
+ "cancel-text",
72
+ "confirm-text",
73
+ "cancel-button-color",
74
+ "confirm-button-color",
75
+ "cancel-text-color",
76
+ "confirm-text-color"
77
+ ];
78
+ }
79
+
80
+ private componentId: string | null = null;
81
+ private mounted = false;
82
+ private unregister?: () => void;
83
+ private _handlers: Record<string, EventListenerOrEventListenerObject> = {};
84
+ private rawHandlers: Record<string, EventListenerOrEventListenerObject> = {};
85
+ private _pageBindings: Record<string, string> = {};
86
+ private harmonyEmbed?: HTMLEmbedElement;
87
+ private lastHarmonyProps?: string;
88
+ private webCleanup?: () => void;
89
+ private attrObserver?: MutationObserver;
90
+ private removeLayoutInvalidationListener?: () => void;
91
+ private readonly layoutInvalidationListener: EventListenerObject = {
92
+ handleEvent: () => {
93
+ if (!this.isConnected || isHarmony() || isDesktop()) return;
94
+ void this.mountPicker();
95
+ }
96
+ };
97
+
98
+ private upgradeProperty(propName: string): void {
99
+ const self = this as unknown as Record<string, unknown>;
100
+ if (!Object.prototype.hasOwnProperty.call(self, propName)) return;
101
+ const value = self[propName];
102
+ delete self[propName];
103
+ self[propName] = value;
104
+ }
105
+
106
+ set pageBindings(bindings: Record<string, string>) {
107
+ this._pageBindings = bindings ?? {};
108
+ if (this.isConnected) {
109
+ this.mountPicker();
110
+ }
111
+ }
112
+
113
+ get pageBindings(): Record<string, string> {
114
+ return this._pageBindings;
115
+ }
116
+
117
+ connectedCallback() {
118
+ this.upgradeProperty("pageBindings");
119
+ this.upgradeProperty("onchange");
120
+
121
+ this.componentId = ensureComponentId(this, "lx-picker", this.componentId);
122
+ if (!this.componentId) return;
123
+
124
+ this.unregister = registerNativeComponentHandler(this.componentId!, (message) => {
125
+ if (typeof message.event === "string") {
126
+ this.dispatchEvent(new CustomEvent(message.event, { detail: message.detail ?? {}, bubbles: true }));
127
+ }
128
+ });
129
+
130
+ this.startAttrObserver();
131
+ if (isAndroid()) {
132
+ this.removeLayoutInvalidationListener = addNativeComponentLayoutInvalidationListener(this.layoutInvalidationListener);
133
+ }
134
+ this.mountPicker();
135
+ queueMicrotask(() => {
136
+ if (!this.isConnected) return;
137
+ this.mountPicker();
138
+ });
139
+ }
140
+
141
+ disconnectedCallback() {
142
+ if (this.webCleanup) {
143
+ this.webCleanup();
144
+ this.webCleanup = undefined;
145
+ }
146
+ this.removeLayoutInvalidationListener?.();
147
+ this.removeLayoutInvalidationListener = undefined;
148
+
149
+ if (this.componentId && !isHarmony() && !isDesktop()) {
150
+ sendNativeComponentMessage({
151
+ action: "component.unmount",
152
+ id: this.componentId
153
+ });
154
+ }
155
+ if (this.unregister) {
156
+ this.unregister();
157
+ this.unregister = undefined;
158
+ }
159
+ if (this.harmonyEmbed && this.contains(this.harmonyEmbed)) {
160
+ this.removeChild(this.harmonyEmbed);
161
+ }
162
+ this.harmonyEmbed = undefined;
163
+ this.lastHarmonyProps = undefined;
164
+ this.mounted = false;
165
+ this.stopAttrObserver();
166
+ Object.keys(this._handlers).forEach(name => {
167
+ this.removeEventListener(name, this._handlers[name]);
168
+ });
169
+ this._handlers = {};
170
+ this.rawHandlers = {};
171
+ }
172
+
173
+ attributeChangedCallback(name: string) {
174
+ if (name === "id") {
175
+ const prev = this.componentId;
176
+ this.componentId = ensureComponentId(this, "lx-picker", this.componentId);
177
+ if (prev && this.componentId !== prev) {
178
+ this.mounted = false;
179
+ }
180
+ }
181
+ if (!this.isConnected) return;
182
+ this.mountPicker();
183
+ }
184
+
185
+ private getAttr(name: string, fallback = "") {
186
+ return this.getAttribute(name) || fallback;
187
+ }
188
+
189
+ private getJsonAttr(name: string) {
190
+ const raw = this.getAttribute(name);
191
+ if (!raw) return undefined;
192
+ try { return JSON.parse(raw); } catch { return undefined; }
193
+ }
194
+
195
+ private collectProps() {
196
+ const mode = this.getAttr("mode", "selector");
197
+ const isDateMode = mode === "date" || mode === "time";
198
+ const fields = this.getAttr("fields");
199
+
200
+ const props: Record<string, any> = {
201
+ mode,
202
+ cancelText: this.getAttr("cancel-text", ""),
203
+ confirmText: this.getAttr("confirm-text", ""),
204
+ cancelButtonColor: this.getAttr("cancel-button-color"),
205
+ confirmButtonColor: this.getAttr("confirm-button-color"),
206
+ cancelTextColor: this.getAttr("cancel-text-color"),
207
+ confirmTextColor: this.getAttr("confirm-text-color")
208
+ };
209
+
210
+ if (isDateMode) {
211
+ if (fields) props.fields = fields;
212
+ const value = this.getAttr("value");
213
+ if (value) {
214
+ props.value = fields === "range" ? this.getJsonAttr("value") : value;
215
+ }
216
+
217
+ const start = this.getAttr("start");
218
+ if (start) props.start = start;
219
+
220
+ const end = this.getAttr("end");
221
+ if (end) props.end = end;
222
+ } else {
223
+ props.columns = this.getJsonAttr("columns");
224
+ props.defaultIndex = this.getJsonAttr("default-index");
225
+ }
226
+
227
+ return props;
228
+ }
229
+
230
+ private shouldRefreshForAttribute(name: string): boolean {
231
+ const normalized = name.trim().toLowerCase();
232
+ return normalized.startsWith("data-");
233
+ }
234
+
235
+ private startAttrObserver(): void {
236
+ if (typeof MutationObserver === "undefined" || this.attrObserver) {
237
+ return;
238
+ }
239
+ this.attrObserver = new MutationObserver((mutations) => {
240
+ for (const mutation of mutations) {
241
+ const attrName = mutation.attributeName;
242
+ if (!attrName || !this.shouldRefreshForAttribute(attrName)) {
243
+ continue;
244
+ }
245
+ this.mountPicker();
246
+ break;
247
+ }
248
+ });
249
+ this.attrObserver.observe(this, { attributes: true });
250
+ }
251
+
252
+ private stopAttrObserver(): void {
253
+ if (!this.attrObserver) {
254
+ return;
255
+ }
256
+ this.attrObserver.disconnect();
257
+ this.attrObserver = undefined;
258
+ }
259
+
260
+ private dataAttrToDatasetKey(attr: string): string {
261
+ const raw = attr.slice(5).trim();
262
+ if (!raw) return "";
263
+ const parts = raw.split("-").filter(Boolean);
264
+ if (parts.length === 0) return "";
265
+ return parts
266
+ .map((segment, index) => {
267
+ if (index === 0) return segment.toLowerCase();
268
+ return segment.charAt(0).toUpperCase() + segment.slice(1);
269
+ })
270
+ .join("");
271
+ }
272
+
273
+ private collectDataset(): Record<string, string> {
274
+ const dataset: Record<string, string> = {};
275
+ const attrs = this.getAttributeNames();
276
+ for (const attr of attrs) {
277
+ if (!attr.startsWith("data-")) continue;
278
+ const key = this.dataAttrToDatasetKey(attr);
279
+ if (!key) continue;
280
+ const value = this.getAttribute(attr);
281
+ if (value == null) continue;
282
+ dataset[key] = value;
283
+ }
284
+ return dataset;
285
+ }
286
+
287
+ private async mountPicker() {
288
+ if (!this.componentId) return;
289
+
290
+ const props = this.collectProps();
291
+ const dataset = this.collectDataset();
292
+ props.dataset = dataset;
293
+ props.datasetJson = JSON.stringify(dataset);
294
+ props.pageFuncBindings = this._pageBindings;
295
+ props.pageFuncBindingsJson = JSON.stringify(this._pageBindings);
296
+ const { rect, cornerRadius } = measureElement(this);
297
+
298
+ if (isHarmony()) {
299
+ this.ensureHarmonyEmbed(rect, props, cornerRadius);
300
+ this.mounted = true;
301
+ return;
302
+ }
303
+
304
+ if (isDesktop()) {
305
+ if (this.webCleanup) return;
306
+ const { renderWebPicker } = await import('./picker-web.js');
307
+ if (!this.isConnected || !this.componentId || this.webCleanup) return;
308
+ this.webCleanup = renderWebPicker(this, props, (detail) => {
309
+ this.dispatchEvent(new CustomEvent('change', { detail, bubbles: true }));
310
+ });
311
+ this.mounted = true;
312
+ return;
313
+ }
314
+
315
+ const payload: any = {
316
+ action: this.mounted ? "component.update" : "component.mount",
317
+ id: this.componentId,
318
+ type: "picker.native",
319
+ rect,
320
+ zIndex: 9999,
321
+ props: props
322
+ };
323
+
324
+ if (cornerRadius !== undefined) {
325
+ payload.cornerRadius = cornerRadius;
326
+ }
327
+
328
+ sendNativeComponentMessage(payload);
329
+ this.mounted = true;
330
+ }
331
+
332
+ // Event handler getter/setter for 'change' event
333
+ set onchange(cb: EventListener | null) {
334
+ const raw = cb as unknown;
335
+ const current = this._handlers['change'];
336
+ if (current) this.removeEventListener('change', current);
337
+
338
+ if (
339
+ typeof raw === "function" ||
340
+ (!!raw && typeof raw === "object" && typeof (raw as EventListenerObject).handleEvent === "function")
341
+ ) {
342
+ const listener =
343
+ typeof raw === "function"
344
+ ? ({ handleEvent: raw } as EventListenerObject)
345
+ : (raw as EventListenerOrEventListenerObject);
346
+ this._handlers['change'] = listener;
347
+ this.rawHandlers['change'] = raw as EventListenerOrEventListenerObject;
348
+ this.addEventListener('change', listener);
349
+ } else {
350
+ delete this._handlers['change'];
351
+ delete this.rawHandlers['change'];
352
+ }
353
+ }
354
+ get onchange() { return (this.rawHandlers['change'] as EventListener) || null; }
355
+
356
+ private ensureHarmonyEmbed(
357
+ rect: { width: number; height: number },
358
+ props: Record<string, unknown>,
359
+ cornerRadius?: number
360
+ ) {
361
+ // Create embed element only once
362
+ if (!this.harmonyEmbed) {
363
+ const embed = document.createElement("embed");
364
+ embed.setAttribute("type", "native/picker");
365
+ embed.setAttribute("width", `${rect.width}`);
366
+ embed.setAttribute("height", `${rect.height}`);
367
+ embed.setAttribute("id", this.componentId!);
368
+ embed.setAttribute("data-lx-component-id", this.componentId!);
369
+ embed.style.display = "block";
370
+ embed.style.width = "100%";
371
+ embed.style.height = "100%";
372
+ embed.style.border = "none";
373
+ if (cornerRadius !== undefined) {
374
+ embed.style.borderRadius = `${cornerRadius}px`;
375
+ embed.style.overflow = "hidden";
376
+ }
377
+
378
+ const encodedProps = this.encodeHarmonyProps(props);
379
+ embed.setAttribute("src", encodedProps);
380
+ this.lastHarmonyProps = encodedProps;
381
+
382
+ this.appendChild(embed);
383
+ this.harmonyEmbed = embed;
384
+ return;
385
+ }
386
+
387
+ // Only update props via src if they actually changed
388
+ const encodedProps = this.encodeHarmonyProps(props);
389
+ if (encodedProps !== this.lastHarmonyProps) {
390
+ this.harmonyEmbed.setAttribute("src", encodedProps);
391
+ this.lastHarmonyProps = encodedProps;
392
+ }
393
+
394
+ // Ensure embed element matches latest corner radius for clipping
395
+ if (cornerRadius !== undefined && this.harmonyEmbed.style.borderRadius !== `${cornerRadius}px`) {
396
+ this.harmonyEmbed.style.borderRadius = `${cornerRadius}px`;
397
+ this.harmonyEmbed.style.overflow = "hidden";
398
+ }
399
+ }
400
+
401
+ private encodeHarmonyProps(props: Record<string, unknown>): string {
402
+ try {
403
+ const payload = { componentId: this.componentId, ...props };
404
+ return `${HARMONY_PROPS_PREFIX}${encodeURIComponent(
405
+ JSON.stringify(payload)
406
+ )}`;
407
+ } catch (_e) {
408
+ return `${HARMONY_PROPS_PREFIX}%7B%7D`;
409
+ }
410
+ }
411
+ }
412
+
413
+ // Register the custom element
414
+ export function registerPickerComponent() {
415
+ if (typeof window !== "undefined" && !customElements.get("lx-picker")) {
416
+ customElements.define("lx-picker", LxPickerElement);
417
+ }
418
+ }
@@ -0,0 +1,25 @@
1
+ import type {} from '@lingxia/bridge';
2
+
3
+ export function isHarmony(): boolean {
4
+ return window.LingXiaBridge?.platform?.isHarmony?.() === true;
5
+ }
6
+
7
+ export function isIOS(): boolean {
8
+ return window.LingXiaBridge?.platform?.isIOS?.() === true;
9
+ }
10
+
11
+ export function isAndroid(): boolean {
12
+ return window.LingXiaBridge?.platform?.isAndroid?.() === true;
13
+ }
14
+
15
+ export function isMacOS(): boolean {
16
+ return window.LingXiaBridge?.platform?.isMacOS?.() === true;
17
+ }
18
+
19
+ export function isDesktop(): boolean {
20
+ return window.LingXiaBridge?.platform?.isDesktop?.() === true;
21
+ }
22
+
23
+ export function getOS(): string {
24
+ return window.LingXiaBridge?.platform?.getOS?.() ?? "unknown";
25
+ }
@@ -0,0 +1,137 @@
1
+ import { appendDataAttrs } from "./native_component_wrapper_shared.js";
2
+
3
+ export interface InputNativeAttrOptions {
4
+ id?: string;
5
+ modelValue?: string;
6
+ value?: string;
7
+ defaultValue?: string;
8
+ type?: "text" | "number" | "password" | "digit";
9
+ password?: boolean;
10
+ placeholder?: string;
11
+ placeholderStyle?: string;
12
+ placeholderClass?: string;
13
+ maxlength?: number;
14
+ cursorSpacing?: number;
15
+ autoFocus?: boolean;
16
+ disabled?: boolean;
17
+ focus?: boolean;
18
+ confirmType?: "send" | "search" | "next" | "go" | "done";
19
+ alwaysEmbed?: boolean;
20
+ confirmHold?: boolean;
21
+ cursor?: number;
22
+ cursorColor?: string;
23
+ selectionStart?: number;
24
+ selectionEnd?: number;
25
+ adjustPosition?: boolean;
26
+ holdKeyboard?: boolean;
27
+ }
28
+
29
+ export interface TextareaNativeAttrOptions {
30
+ id?: string;
31
+ modelValue?: string;
32
+ value?: string;
33
+ defaultValue?: string;
34
+ placeholder?: string;
35
+ placeholderStyle?: string;
36
+ placeholderClass?: string;
37
+ maxlength?: number;
38
+ disabled?: boolean;
39
+ autoFocus?: boolean;
40
+ focus?: boolean;
41
+ autoHeight?: boolean;
42
+ cursorSpacing?: number;
43
+ showConfirmBar?: boolean;
44
+ adjustPosition?: boolean;
45
+ holdKeyboard?: boolean;
46
+ disableDefaultPadding?: boolean;
47
+ confirmType?: "send" | "search" | "next" | "go" | "done" | "return";
48
+ confirmHold?: boolean;
49
+ fixed?: boolean;
50
+ adjustKeyboardTo?: "cursor" | "bottom";
51
+ cursor?: number;
52
+ selectionStart?: number;
53
+ selectionEnd?: number;
54
+ }
55
+
56
+ export function buildInputNativeAttrs(
57
+ options: InputNativeAttrOptions,
58
+ extraAttrs: Record<string, unknown> = {},
59
+ mounted = false
60
+ ): Record<string, string> {
61
+ const result: Record<string, string> = {};
62
+ const explicitId = typeof options.id === "string" ? options.id.trim() : "";
63
+
64
+ if (explicitId.length > 0) result.id = explicitId;
65
+
66
+ const nextValue = options.modelValue ?? options.value;
67
+ if (nextValue !== undefined) {
68
+ result.value = nextValue;
69
+ } else if (!mounted && options.defaultValue !== undefined) {
70
+ result.value = options.defaultValue;
71
+ }
72
+
73
+ if (options.type) result.type = options.type;
74
+ if (options.password) result.password = "true";
75
+ if (options.placeholder) result.placeholder = options.placeholder;
76
+ if (options.placeholderStyle) result["placeholder-style"] = options.placeholderStyle;
77
+ if (options.placeholderClass) result["placeholder-class"] = options.placeholderClass;
78
+ if (options.maxlength !== undefined) result.maxlength = String(options.maxlength);
79
+ if (options.cursorSpacing !== undefined) result["cursor-spacing"] = String(options.cursorSpacing);
80
+ if (options.autoFocus) result["auto-focus"] = "true";
81
+ if (options.disabled) result.disabled = "true";
82
+ if (options.focus !== undefined) result.focus = options.focus ? "true" : "false";
83
+ if (options.confirmType) result["confirm-type"] = options.confirmType;
84
+ if (options.alwaysEmbed) result["always-embed"] = "true";
85
+ if (options.confirmHold) result["confirm-hold"] = "true";
86
+ if (options.cursor !== undefined) result.cursor = String(options.cursor);
87
+ if (options.cursorColor) result["cursor-color"] = options.cursorColor;
88
+ if (options.selectionStart !== undefined) result["selection-start"] = String(options.selectionStart);
89
+ if (options.selectionEnd !== undefined) result["selection-end"] = String(options.selectionEnd);
90
+ if (options.adjustPosition === false) result["adjust-position"] = "false";
91
+ if (options.holdKeyboard) result["hold-keyboard"] = "true";
92
+
93
+ appendDataAttrs(extraAttrs, result);
94
+ return result;
95
+ }
96
+
97
+ export function buildTextareaNativeAttrs(
98
+ options: TextareaNativeAttrOptions,
99
+ extraAttrs: Record<string, unknown> = {},
100
+ mounted = false
101
+ ): Record<string, string> {
102
+ const result: Record<string, string> = {};
103
+ const explicitId = typeof options.id === "string" ? options.id.trim() : "";
104
+
105
+ if (explicitId.length > 0) result.id = explicitId;
106
+
107
+ const nextValue = options.modelValue ?? options.value;
108
+ if (nextValue !== undefined) {
109
+ result.value = nextValue;
110
+ } else if (!mounted && options.defaultValue !== undefined) {
111
+ result.value = options.defaultValue;
112
+ }
113
+
114
+ if (options.placeholder) result.placeholder = options.placeholder;
115
+ if (options.placeholderStyle) result["placeholder-style"] = options.placeholderStyle;
116
+ if (options.placeholderClass) result["placeholder-class"] = options.placeholderClass;
117
+ if (options.maxlength !== undefined) result.maxlength = String(options.maxlength);
118
+ if (options.disabled) result.disabled = "true";
119
+ if (options.autoFocus) result["auto-focus"] = "true";
120
+ if (options.focus !== undefined) result.focus = options.focus ? "true" : "false";
121
+ if (options.autoHeight) result["auto-height"] = "true";
122
+ if (options.cursorSpacing !== undefined) result["cursor-spacing"] = String(options.cursorSpacing);
123
+ if (options.showConfirmBar === false) result["show-confirm-bar"] = "false";
124
+ if (options.adjustPosition === false) result["adjust-position"] = "false";
125
+ if (options.holdKeyboard) result["hold-keyboard"] = "true";
126
+ if (options.disableDefaultPadding) result["disable-default-padding"] = "true";
127
+ if (options.confirmType) result["confirm-type"] = options.confirmType;
128
+ if (options.confirmHold) result["confirm-hold"] = "true";
129
+ if (options.fixed) result.fixed = "true";
130
+ if (options.adjustKeyboardTo) result["adjust-keyboard-to"] = options.adjustKeyboardTo;
131
+ if (options.cursor !== undefined) result.cursor = String(options.cursor);
132
+ if (options.selectionStart !== undefined) result["selection-start"] = String(options.selectionStart);
133
+ if (options.selectionEnd !== undefined) result["selection-end"] = String(options.selectionEnd);
134
+
135
+ appendDataAttrs(extraAttrs, result);
136
+ return result;
137
+ }