selective-ui 1.3.1 → 1.4.1
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/selective-ui.css +0 -6
- package/dist/selective-ui.css.map +1 -1
- package/dist/selective-ui.esm.js +271 -559
- package/dist/selective-ui.esm.js.map +1 -1
- package/dist/selective-ui.esm.min.js +2 -2
- package/dist/selective-ui.esm.min.js.br +0 -0
- package/dist/selective-ui.min.css +1 -1
- package/dist/selective-ui.min.css.br +0 -0
- package/dist/selective-ui.min.js +2 -2
- package/dist/selective-ui.min.js.br +0 -0
- package/dist/selective-ui.umd.js +273 -561
- package/dist/selective-ui.umd.js.map +1 -1
- package/package.json +12 -12
- package/src/ts/adapter/mixed-adapter.ts +147 -68
- package/src/ts/components/accessorybox.ts +14 -11
- package/src/ts/components/directive.ts +1 -1
- package/src/ts/components/option-handle.ts +12 -9
- package/src/ts/components/placeholder.ts +5 -5
- package/src/ts/components/popup/empty-state.ts +5 -5
- package/src/ts/components/popup/loading-state.ts +5 -5
- package/src/ts/components/popup/popup.ts +138 -76
- package/src/ts/components/searchbox.ts +17 -13
- package/src/ts/components/selectbox.ts +258 -83
- package/src/ts/core/base/adapter.ts +39 -14
- package/src/ts/core/base/fenwick.ts +3 -2
- package/src/ts/core/base/lifecycle.ts +14 -4
- package/src/ts/core/base/model.ts +17 -15
- package/src/ts/core/base/recyclerview.ts +7 -5
- package/src/ts/core/base/view.ts +10 -5
- package/src/ts/core/base/virtual-recyclerview.ts +89 -37
- package/src/ts/core/model-manager.ts +48 -21
- package/src/ts/core/search-controller.ts +174 -56
- package/src/ts/global.ts +5 -8
- package/src/ts/index.ts +2 -2
- package/src/ts/models/group-model.ts +33 -8
- package/src/ts/models/option-model.ts +60 -19
- package/src/ts/services/dataset-observer.ts +6 -3
- package/src/ts/services/ea-observer.ts +1 -1
- package/src/ts/services/effector.ts +22 -12
- package/src/ts/services/refresher.ts +7 -3
- package/src/ts/services/resize-observer.ts +24 -11
- package/src/ts/services/select-observer.ts +2 -2
- package/src/ts/types/components/popup.type.ts +18 -1
- package/src/ts/types/components/searchbox.type.ts +43 -30
- package/src/ts/types/components/state.box.type.ts +1 -1
- package/src/ts/types/core/base/adapter.type.ts +13 -5
- package/src/ts/types/core/base/lifecycle.type.ts +1 -2
- package/src/ts/types/core/base/model.type.ts +3 -3
- package/src/ts/types/core/base/recyclerview.type.ts +7 -5
- package/src/ts/types/core/base/view.type.ts +6 -6
- package/src/ts/types/core/base/virtual-recyclerview.type.ts +45 -46
- package/src/ts/types/core/search-controller.type.ts +18 -2
- package/src/ts/types/css.d.ts +1 -0
- package/src/ts/types/plugins/plugin.type.ts +2 -2
- package/src/ts/types/services/effector.type.ts +25 -25
- package/src/ts/types/services/resize-observer.type.ts +23 -12
- package/src/ts/types/utils/callback-scheduler.type.ts +2 -2
- package/src/ts/types/utils/ievents.type.ts +1 -1
- package/src/ts/types/utils/istorage.type.ts +62 -60
- package/src/ts/types/utils/libs.type.ts +19 -17
- package/src/ts/types/utils/selective.type.ts +6 -3
- package/src/ts/types/views/view.group.type.ts +9 -5
- package/src/ts/types/views/view.option.type.ts +39 -17
- package/src/ts/utils/callback-scheduler.ts +12 -7
- package/src/ts/utils/ievents.ts +12 -5
- package/src/ts/utils/istorage.ts +5 -3
- package/src/ts/utils/libs.ts +122 -43
- package/src/ts/utils/selective.ts +15 -8
- package/src/ts/views/group-view.ts +11 -9
- package/src/ts/views/option-view.ts +37 -18
|
@@ -43,7 +43,12 @@ import { LifecycleState } from "../types/core/base/lifecycle.type";
|
|
|
43
43
|
* @see {@link OptionModel}
|
|
44
44
|
* @see {@link GroupView}
|
|
45
45
|
*/
|
|
46
|
-
export class GroupModel extends Model<
|
|
46
|
+
export class GroupModel extends Model<
|
|
47
|
+
HTMLOptGroupElement,
|
|
48
|
+
GroupViewTags,
|
|
49
|
+
GroupView,
|
|
50
|
+
SelectiveOptions
|
|
51
|
+
> {
|
|
47
52
|
/** Group label (mirrors `HTMLSelectOptGroupElement.label`). */
|
|
48
53
|
public label = "";
|
|
49
54
|
|
|
@@ -67,7 +72,13 @@ export class GroupModel extends Model<HTMLOptGroupElement, GroupViewTags, GroupV
|
|
|
67
72
|
* Subscribers invoked when collapsed state changes.
|
|
68
73
|
* Callbacks are invoked through {@link iEvents.callEvent}.
|
|
69
74
|
*/
|
|
70
|
-
private privOnCollapsedChanged: Array<
|
|
75
|
+
private privOnCollapsedChanged: Array<
|
|
76
|
+
(
|
|
77
|
+
evtToken: IEventCallback,
|
|
78
|
+
model: GroupModel,
|
|
79
|
+
collapsed: boolean,
|
|
80
|
+
) => void
|
|
81
|
+
> = [];
|
|
71
82
|
|
|
72
83
|
/**
|
|
73
84
|
* Creates a group model from configuration and an optional `<optgroup>` element.
|
|
@@ -75,10 +86,15 @@ export class GroupModel extends Model<HTMLOptGroupElement, GroupViewTags, GroupV
|
|
|
75
86
|
* @param {SelectiveOptions} options - Shared configuration for models/views.
|
|
76
87
|
* @param {HTMLOptGroupElement} [targetElement] - Backing `<optgroup>` element (when available).
|
|
77
88
|
*/
|
|
78
|
-
public constructor(
|
|
89
|
+
public constructor(
|
|
90
|
+
options: SelectiveOptions,
|
|
91
|
+
targetElement?: HTMLOptGroupElement,
|
|
92
|
+
) {
|
|
79
93
|
super(options, targetElement ?? null, null);
|
|
80
94
|
this.label = this.targetElement.label;
|
|
81
|
-
this.collapsed = Libs.string2Boolean(
|
|
95
|
+
this.collapsed = Libs.string2Boolean(
|
|
96
|
+
this.targetElement.dataset?.collapsed,
|
|
97
|
+
);
|
|
82
98
|
}
|
|
83
99
|
|
|
84
100
|
/**
|
|
@@ -189,7 +205,7 @@ export class GroupModel extends Model<HTMLOptGroupElement, GroupViewTags, GroupV
|
|
|
189
205
|
return;
|
|
190
206
|
}
|
|
191
207
|
|
|
192
|
-
this.items.forEach(item => {
|
|
208
|
+
this.items.forEach((item) => {
|
|
193
209
|
item.destroy();
|
|
194
210
|
});
|
|
195
211
|
|
|
@@ -206,7 +222,13 @@ export class GroupModel extends Model<HTMLOptGroupElement, GroupViewTags, GroupV
|
|
|
206
222
|
* Listener invoked with `(evtToken, model, collapsed)`.
|
|
207
223
|
* @returns {void}
|
|
208
224
|
*/
|
|
209
|
-
public onCollapsedChanged(
|
|
225
|
+
public onCollapsedChanged(
|
|
226
|
+
callback: (
|
|
227
|
+
evtToken: IEventCallback,
|
|
228
|
+
model: GroupModel,
|
|
229
|
+
collapsed: boolean,
|
|
230
|
+
) => void,
|
|
231
|
+
): void {
|
|
210
232
|
this.privOnCollapsedChanged.push(callback);
|
|
211
233
|
}
|
|
212
234
|
|
|
@@ -224,7 +246,10 @@ export class GroupModel extends Model<HTMLOptGroupElement, GroupViewTags, GroupV
|
|
|
224
246
|
this.collapsed = !this.collapsed;
|
|
225
247
|
this.view?.setCollapsed(this.collapsed);
|
|
226
248
|
|
|
227
|
-
iEvents.callEvent<[GroupModel, boolean]>(
|
|
249
|
+
iEvents.callEvent<[GroupModel, boolean]>(
|
|
250
|
+
[this, this.collapsed],
|
|
251
|
+
...this.privOnCollapsedChanged,
|
|
252
|
+
);
|
|
228
253
|
}
|
|
229
254
|
|
|
230
255
|
/**
|
|
@@ -267,4 +292,4 @@ export class GroupModel extends Model<HTMLOptGroupElement, GroupViewTags, GroupV
|
|
|
267
292
|
public updateVisibility(): void {
|
|
268
293
|
this.view?.updateVisibility();
|
|
269
294
|
}
|
|
270
|
-
}
|
|
295
|
+
}
|
|
@@ -55,24 +55,35 @@ import { LifecycleState } from "../types/core/base/lifecycle.type";
|
|
|
55
55
|
* @see {@link GroupModel}
|
|
56
56
|
* @see {@link OptionView}
|
|
57
57
|
*/
|
|
58
|
-
export class OptionModel extends Model<
|
|
58
|
+
export class OptionModel extends Model<
|
|
59
|
+
HTMLOptionElement,
|
|
60
|
+
OptionViewTags,
|
|
61
|
+
OptionView,
|
|
62
|
+
SelectiveOptions
|
|
63
|
+
> {
|
|
59
64
|
/**
|
|
60
65
|
* External selection subscribers (emitted by the {@link selected} setter).
|
|
61
66
|
* Use this for user-facing selection flows.
|
|
62
67
|
*/
|
|
63
|
-
private privOnSelected: Array<
|
|
68
|
+
private privOnSelected: Array<
|
|
69
|
+
(evtToken: IEventCallback, el: OptionModel, selected: boolean) => void
|
|
70
|
+
> = [];
|
|
64
71
|
|
|
65
72
|
/**
|
|
66
73
|
* Internal selection subscribers (emitted by the {@link selectedNonTrigger} setter).
|
|
67
74
|
* Use this for silent synchronization flows.
|
|
68
75
|
*/
|
|
69
|
-
private privOnInternalSelected: Array<
|
|
76
|
+
private privOnInternalSelected: Array<
|
|
77
|
+
(evtToken: IEventCallback, el: OptionModel, selected: boolean) => void
|
|
78
|
+
> = [];
|
|
70
79
|
|
|
71
80
|
/**
|
|
72
81
|
* Visibility subscribers (emitted by the {@link visible} setter).
|
|
73
82
|
* Commonly used to recompute group visibility and update aggregated visibility stats.
|
|
74
83
|
*/
|
|
75
|
-
private privOnVisibilityChanged: Array<
|
|
84
|
+
private privOnVisibilityChanged: Array<
|
|
85
|
+
(evtToken: IEventCallback, model: OptionModel, visible: boolean) => void
|
|
86
|
+
> = [];
|
|
76
87
|
|
|
77
88
|
/**
|
|
78
89
|
* Visibility flag used for filtering/search.
|
|
@@ -87,19 +98,19 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
|
|
|
87
98
|
* Parent group model (if this option belongs to a group).
|
|
88
99
|
* Assigned by grouping logic (e.g., GroupModel/MixedAdapter).
|
|
89
100
|
*/
|
|
90
|
-
public group
|
|
101
|
+
public group?: GroupModel;
|
|
91
102
|
|
|
92
103
|
/**
|
|
93
104
|
* Creates an option model.
|
|
94
105
|
*
|
|
95
106
|
* @param {SelectiveOptions} options - Shared configuration for models/views.
|
|
96
|
-
* @param {HTMLOptionElement
|
|
97
|
-
* @param {OptionView
|
|
107
|
+
* @param {HTMLOptionElement} [targetElement=null] - Backing `<option>` element.
|
|
108
|
+
* @param {OptionView} [view=null] - Optional view used to render this model.
|
|
98
109
|
*/
|
|
99
110
|
public constructor(
|
|
100
111
|
options: SelectiveOptions,
|
|
101
|
-
targetElement
|
|
102
|
-
view
|
|
112
|
+
targetElement?: HTMLOptionElement,
|
|
113
|
+
view?: OptionView,
|
|
103
114
|
) {
|
|
104
115
|
super(options, targetElement, view);
|
|
105
116
|
}
|
|
@@ -168,7 +179,10 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
|
|
|
168
179
|
*/
|
|
169
180
|
public set selected(value: boolean) {
|
|
170
181
|
this.selectedNonTrigger = value;
|
|
171
|
-
iEvents.callEvent<[OptionModel, boolean]>(
|
|
182
|
+
iEvents.callEvent<[OptionModel, boolean]>(
|
|
183
|
+
[this, value],
|
|
184
|
+
...this.privOnSelected,
|
|
185
|
+
);
|
|
172
186
|
}
|
|
173
187
|
|
|
174
188
|
/**
|
|
@@ -199,7 +213,10 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
|
|
|
199
213
|
const viewEl = this.view?.getView?.();
|
|
200
214
|
if (viewEl) viewEl.classList.toggle("hide", !value);
|
|
201
215
|
|
|
202
|
-
iEvents.callEvent<[OptionModel, boolean]>(
|
|
216
|
+
iEvents.callEvent<[OptionModel, boolean]>(
|
|
217
|
+
[this, value],
|
|
218
|
+
...this.privOnVisibilityChanged,
|
|
219
|
+
);
|
|
203
220
|
}
|
|
204
221
|
|
|
205
222
|
/**
|
|
@@ -243,7 +260,10 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
|
|
|
243
260
|
this.targetElement.selected = value;
|
|
244
261
|
}
|
|
245
262
|
|
|
246
|
-
iEvents.callEvent<[OptionModel, boolean]>(
|
|
263
|
+
iEvents.callEvent<[OptionModel, boolean]>(
|
|
264
|
+
[this, value],
|
|
265
|
+
...this.privOnInternalSelected,
|
|
266
|
+
);
|
|
247
267
|
}
|
|
248
268
|
|
|
249
269
|
/**
|
|
@@ -273,7 +293,9 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
|
|
|
273
293
|
* @returns {string}
|
|
274
294
|
*/
|
|
275
295
|
public get textContent(): string {
|
|
276
|
-
return this.options.allowHtml
|
|
296
|
+
return this.options.allowHtml
|
|
297
|
+
? Libs.stripHtml(this.text).trim()
|
|
298
|
+
: this.text.trim();
|
|
277
299
|
}
|
|
278
300
|
|
|
279
301
|
/**
|
|
@@ -323,7 +345,13 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
|
|
|
323
345
|
* @param {(evtToken: IEventCallback, el: OptionModel, selected: boolean) => void} callback - Listener callback.
|
|
324
346
|
* @returns {void}
|
|
325
347
|
*/
|
|
326
|
-
public onSelected(
|
|
348
|
+
public onSelected(
|
|
349
|
+
callback: (
|
|
350
|
+
evtToken: IEventCallback,
|
|
351
|
+
el: OptionModel,
|
|
352
|
+
selected: boolean,
|
|
353
|
+
) => void,
|
|
354
|
+
): void {
|
|
327
355
|
this.privOnSelected.push(callback);
|
|
328
356
|
}
|
|
329
357
|
|
|
@@ -333,7 +361,13 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
|
|
|
333
361
|
* @param {(evtToken: IEventCallback, el: OptionModel, selected: boolean) => void} callback - Listener callback.
|
|
334
362
|
* @returns {void}
|
|
335
363
|
*/
|
|
336
|
-
public onInternalSelected(
|
|
364
|
+
public onInternalSelected(
|
|
365
|
+
callback: (
|
|
366
|
+
evtToken: IEventCallback,
|
|
367
|
+
el: OptionModel,
|
|
368
|
+
selected: boolean,
|
|
369
|
+
) => void,
|
|
370
|
+
): void {
|
|
337
371
|
this.privOnInternalSelected.push(callback);
|
|
338
372
|
}
|
|
339
373
|
|
|
@@ -343,7 +377,13 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
|
|
|
343
377
|
* @param {(evtToken: IEventCallback, model: OptionModel, visible: boolean) => void} callback - Listener callback.
|
|
344
378
|
* @returns {void}
|
|
345
379
|
*/
|
|
346
|
-
public onVisibilityChanged(
|
|
380
|
+
public onVisibilityChanged(
|
|
381
|
+
callback: (
|
|
382
|
+
evtToken: IEventCallback,
|
|
383
|
+
model: OptionModel,
|
|
384
|
+
visible: boolean,
|
|
385
|
+
) => void,
|
|
386
|
+
): void {
|
|
347
387
|
this.privOnVisibilityChanged.push(callback);
|
|
348
388
|
}
|
|
349
389
|
|
|
@@ -389,7 +429,8 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
|
|
|
389
429
|
}
|
|
390
430
|
}
|
|
391
431
|
|
|
392
|
-
if (this.targetElement)
|
|
432
|
+
if (this.targetElement)
|
|
433
|
+
this.selectedNonTrigger = this.targetElement.selected;
|
|
393
434
|
|
|
394
435
|
super.update();
|
|
395
436
|
}
|
|
@@ -416,7 +457,7 @@ export class OptionModel extends Model<HTMLOptionElement, OptionViewTags, Option
|
|
|
416
457
|
this.privOnVisibilityChanged = [];
|
|
417
458
|
this.group = null;
|
|
418
459
|
this.textToFind = null;
|
|
419
|
-
|
|
460
|
+
|
|
420
461
|
super.destroy();
|
|
421
462
|
}
|
|
422
|
-
}
|
|
463
|
+
}
|
|
@@ -38,7 +38,7 @@ export class DatasetObserver {
|
|
|
38
38
|
* Debounce timer handle for coalescing rapid attribute mutations.
|
|
39
39
|
* Cleared/replaced whenever a new relevant mutation arrives within the debounce window.
|
|
40
40
|
*/
|
|
41
|
-
private debounceTimer
|
|
41
|
+
private debounceTimer?: NodeJS.Timeout;
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* Creates a {@link DatasetObserver} for the given element.
|
|
@@ -62,7 +62,10 @@ export class DatasetObserver {
|
|
|
62
62
|
let datasetChanged = false;
|
|
63
63
|
|
|
64
64
|
for (const mutation of mutations) {
|
|
65
|
-
if (
|
|
65
|
+
if (
|
|
66
|
+
mutation.type === "attributes" &&
|
|
67
|
+
mutation.attributeName?.startsWith("data-")
|
|
68
|
+
) {
|
|
66
69
|
datasetChanged = true;
|
|
67
70
|
break;
|
|
68
71
|
}
|
|
@@ -132,4 +135,4 @@ export class DatasetObserver {
|
|
|
132
135
|
this.debounceTimer = null;
|
|
133
136
|
this.observer.disconnect();
|
|
134
137
|
}
|
|
135
|
-
}
|
|
138
|
+
}
|
|
@@ -27,7 +27,7 @@ import type {
|
|
|
27
27
|
* @param query - CSS selector or element to control. When `null`, the effector is unbound.
|
|
28
28
|
* @returns An effector instance implementing {@link EffectorInterface}.
|
|
29
29
|
*/
|
|
30
|
-
export function Effector(query?: string | HTMLElement
|
|
30
|
+
export function Effector(query?: string | HTMLElement): EffectorInterface {
|
|
31
31
|
return new EffectorImpl(query ?? null);
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -57,13 +57,13 @@ class EffectorImpl implements EffectorInterface {
|
|
|
57
57
|
* Timeout used to finalize expand/collapse/swipe animations.
|
|
58
58
|
* Cleared by {@link cancel}.
|
|
59
59
|
*/
|
|
60
|
-
private timeOut
|
|
60
|
+
private timeOut?: NodeJS.Timeout;
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
* Timeout used to clear transitions after resize in non-animated scenarios.
|
|
64
64
|
* Cleared by {@link cancel}.
|
|
65
65
|
*/
|
|
66
|
-
private resizeTimeout
|
|
66
|
+
private resizeTimeout?: NodeJS.Timeout;
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
69
|
* Internal animation flag set while a timed animation is in-flight.
|
|
@@ -80,7 +80,7 @@ class EffectorImpl implements EffectorInterface {
|
|
|
80
80
|
*
|
|
81
81
|
* @param query - CSS selector or element to control. When `null`, instance starts unbound.
|
|
82
82
|
*/
|
|
83
|
-
public constructor(query
|
|
83
|
+
public constructor(query?: string | HTMLElement) {
|
|
84
84
|
if (query) this.setElement(query);
|
|
85
85
|
}
|
|
86
86
|
|
|
@@ -145,7 +145,9 @@ class EffectorImpl implements EffectorInterface {
|
|
|
145
145
|
* @param display - The display style to use for measurement (defaults to `"flex"`).
|
|
146
146
|
* @returns A dimension snapshot including `scrollHeight` adjusted for vertical borders.
|
|
147
147
|
*/
|
|
148
|
-
public getHiddenDimensions(
|
|
148
|
+
public getHiddenDimensions(
|
|
149
|
+
display: "flex" | string = "flex",
|
|
150
|
+
): DimensionObject {
|
|
149
151
|
// Guard: element may not be set yet.
|
|
150
152
|
if (!this.element) return { width: 0, height: 0, scrollHeight: 0 };
|
|
151
153
|
|
|
@@ -169,7 +171,8 @@ class EffectorImpl implements EffectorInterface {
|
|
|
169
171
|
const borderTopWidth = parseFloat(cs.borderTopWidth);
|
|
170
172
|
const borderBottomWidth = parseFloat(cs.borderBottomWidth);
|
|
171
173
|
|
|
172
|
-
const scrollHeight =
|
|
174
|
+
const scrollHeight =
|
|
175
|
+
this.element.scrollHeight + borderTopWidth + borderBottomWidth;
|
|
173
176
|
const rect = this.element.getBoundingClientRect();
|
|
174
177
|
|
|
175
178
|
const dimensions: DimensionObject = {
|
|
@@ -286,10 +289,14 @@ class EffectorImpl implements EffectorInterface {
|
|
|
286
289
|
|
|
287
290
|
const currentHeight = this.element.offsetHeight;
|
|
288
291
|
const currentTop = this.element.offsetTop;
|
|
289
|
-
const position = this.element.classList.contains("position-top")
|
|
290
|
-
|
|
292
|
+
const position = this.element.classList.contains("position-top")
|
|
293
|
+
? "top"
|
|
294
|
+
: "bottom";
|
|
295
|
+
const isScrollable =
|
|
296
|
+
this.element.scrollHeight - this.element.offsetHeight > 0;
|
|
291
297
|
|
|
292
|
-
const finalTop =
|
|
298
|
+
const finalTop =
|
|
299
|
+
position === "top" ? currentTop + currentHeight : currentTop;
|
|
293
300
|
|
|
294
301
|
requestAnimationFrame(() => {
|
|
295
302
|
Object.assign(this.element.style, {
|
|
@@ -459,7 +466,9 @@ class EffectorImpl implements EffectorInterface {
|
|
|
459
466
|
onComplete,
|
|
460
467
|
} = config;
|
|
461
468
|
|
|
462
|
-
const currentPosition = this.element.classList.contains("position-top")
|
|
469
|
+
const currentPosition = this.element.classList.contains("position-top")
|
|
470
|
+
? "top"
|
|
471
|
+
: "bottom";
|
|
463
472
|
const isPositionChanged = currentPosition !== position;
|
|
464
473
|
const isScrollable = this.element.scrollHeight > maxHeight;
|
|
465
474
|
|
|
@@ -471,7 +480,8 @@ class EffectorImpl implements EffectorInterface {
|
|
|
471
480
|
}
|
|
472
481
|
|
|
473
482
|
requestAnimationFrame(() => {
|
|
474
|
-
const styles: Partial<CSSStyleDeclaration> &
|
|
483
|
+
const styles: Partial<CSSStyleDeclaration> &
|
|
484
|
+
Record<string, string> = {
|
|
475
485
|
width: `${width}px`,
|
|
476
486
|
left: `${left}px`,
|
|
477
487
|
top: `${top}px`,
|
|
@@ -521,4 +531,4 @@ class EffectorImpl implements EffectorInterface {
|
|
|
521
531
|
public get isAnimating(): boolean {
|
|
522
532
|
return this._isAnimating;
|
|
523
533
|
}
|
|
524
|
-
}
|
|
534
|
+
}
|
|
@@ -37,7 +37,10 @@ export class Refresher {
|
|
|
37
37
|
* @param select - Native `<select>` element used as the sizing reference and option source.
|
|
38
38
|
* @param view - View panel element whose inline styles will be updated.
|
|
39
39
|
*/
|
|
40
|
-
public static resizeBox(
|
|
40
|
+
public static resizeBox(
|
|
41
|
+
select: HTMLSelectElement,
|
|
42
|
+
view: HTMLElement,
|
|
43
|
+
): void {
|
|
41
44
|
const bindedMap = Libs.getBinderMap<BinderMap>(select);
|
|
42
45
|
if (!bindedMap?.options) return;
|
|
43
46
|
|
|
@@ -55,11 +58,12 @@ export class Refresher {
|
|
|
55
58
|
const cstyle = getComputedStyle(select);
|
|
56
59
|
|
|
57
60
|
if (width === "0px" && cstyle.width !== "auto") width = cstyle.width;
|
|
58
|
-
if (height === "0px" && cstyle.height !== "auto")
|
|
61
|
+
if (height === "0px" && cstyle.height !== "auto")
|
|
62
|
+
height = cstyle.height;
|
|
59
63
|
|
|
60
64
|
if (cfgWidth > 0) width = options.width;
|
|
61
65
|
if (cfgHeight > 0) height = options.height;
|
|
62
66
|
|
|
63
67
|
Object.assign(view.style, { width, height, minWidth, minHeight });
|
|
64
68
|
}
|
|
65
|
-
}
|
|
69
|
+
}
|
|
@@ -63,7 +63,7 @@ export class ResizeObserverService {
|
|
|
63
63
|
* @remarks
|
|
64
64
|
* Set by {@link connect} and cleared by {@link disconnect}.
|
|
65
65
|
*/
|
|
66
|
-
public element
|
|
66
|
+
public element?: HTMLElement;
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
69
|
* Underlying `ResizeObserver` instance.
|
|
@@ -71,7 +71,7 @@ export class ResizeObserverService {
|
|
|
71
71
|
* @remarks
|
|
72
72
|
* Allocated on {@link connect}. Disconnected and nulled on {@link disconnect}.
|
|
73
73
|
*/
|
|
74
|
-
private resizeObserver
|
|
74
|
+
private resizeObserver?: ResizeObserver;
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
77
|
* Underlying `MutationObserver` instance watching `style` and `class` attribute changes.
|
|
@@ -79,7 +79,7 @@ export class ResizeObserverService {
|
|
|
79
79
|
* @remarks
|
|
80
80
|
* Allocated on {@link connect}. Disconnected and nulled on {@link disconnect}.
|
|
81
81
|
*/
|
|
82
|
-
private mutationObserver
|
|
82
|
+
private mutationObserver?: MutationObserver;
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* Stable, `this`-bound handler shared by observers and global event listeners.
|
|
@@ -115,7 +115,7 @@ export class ResizeObserverService {
|
|
|
115
115
|
* @param metrics - Snapshot of geometry and box edges (padding/border/margin).
|
|
116
116
|
*/
|
|
117
117
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
118
|
-
public onChanged(metrics: ElementMetrics): void {
|
|
118
|
+
public onChanged(metrics: ElementMetrics): void {}
|
|
119
119
|
|
|
120
120
|
/**
|
|
121
121
|
* Computes metrics for the current {@link element} and forwards them to {@link onChanged}.
|
|
@@ -150,7 +150,8 @@ export class ResizeObserverService {
|
|
|
150
150
|
|
|
151
151
|
const rect = el.getBoundingClientRect();
|
|
152
152
|
const style =
|
|
153
|
-
typeof window !== "undefined" &&
|
|
153
|
+
typeof window !== "undefined" &&
|
|
154
|
+
typeof window.getComputedStyle === "function"
|
|
154
155
|
? window.getComputedStyle(el)
|
|
155
156
|
: null;
|
|
156
157
|
|
|
@@ -233,8 +234,14 @@ export class ResizeObserverService {
|
|
|
233
234
|
window.addEventListener("resize", this.boundUpdateChanged);
|
|
234
235
|
|
|
235
236
|
if (window.visualViewport) {
|
|
236
|
-
window.visualViewport.addEventListener(
|
|
237
|
-
|
|
237
|
+
window.visualViewport.addEventListener(
|
|
238
|
+
"resize",
|
|
239
|
+
this.boundUpdateChanged,
|
|
240
|
+
);
|
|
241
|
+
window.visualViewport.addEventListener(
|
|
242
|
+
"scroll",
|
|
243
|
+
this.boundUpdateChanged,
|
|
244
|
+
);
|
|
238
245
|
}
|
|
239
246
|
}
|
|
240
247
|
|
|
@@ -254,18 +261,24 @@ export class ResizeObserverService {
|
|
|
254
261
|
this.resizeObserver?.disconnect();
|
|
255
262
|
this.mutationObserver?.disconnect();
|
|
256
263
|
|
|
257
|
-
this.onChanged = (_metrics: ElementMetrics) => {
|
|
264
|
+
this.onChanged = (_metrics: ElementMetrics) => {};
|
|
258
265
|
|
|
259
266
|
window.removeEventListener("scroll", this.boundUpdateChanged, true);
|
|
260
267
|
window.removeEventListener("resize", this.boundUpdateChanged);
|
|
261
268
|
|
|
262
269
|
if (window.visualViewport) {
|
|
263
|
-
window.visualViewport.removeEventListener(
|
|
264
|
-
|
|
270
|
+
window.visualViewport.removeEventListener(
|
|
271
|
+
"resize",
|
|
272
|
+
this.boundUpdateChanged,
|
|
273
|
+
);
|
|
274
|
+
window.visualViewport.removeEventListener(
|
|
275
|
+
"scroll",
|
|
276
|
+
this.boundUpdateChanged,
|
|
277
|
+
);
|
|
265
278
|
}
|
|
266
279
|
|
|
267
280
|
this.resizeObserver = null;
|
|
268
281
|
this.mutationObserver = null;
|
|
269
282
|
this.element = null;
|
|
270
283
|
}
|
|
271
|
-
}
|
|
284
|
+
}
|
|
@@ -62,7 +62,7 @@ export class SelectObserver {
|
|
|
62
62
|
*
|
|
63
63
|
* @private
|
|
64
64
|
*/
|
|
65
|
-
private debounceTimer
|
|
65
|
+
private debounceTimer?: NodeJS.Timeout;
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
68
|
* Debounce delay in milliseconds.
|
|
@@ -171,4 +171,4 @@ export class SelectObserver {
|
|
|
171
171
|
this.debounceTimer = null;
|
|
172
172
|
this.observer.disconnect();
|
|
173
173
|
}
|
|
174
|
-
}
|
|
174
|
+
}
|
|
@@ -12,4 +12,21 @@ export interface VirtualRecyclerOptions {
|
|
|
12
12
|
estimateItemHeight?: number;
|
|
13
13
|
overscan?: number;
|
|
14
14
|
dynamicHeights?: boolean;
|
|
15
|
-
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface PopupPosition {
|
|
18
|
+
position: "top" | "bottom";
|
|
19
|
+
top: number;
|
|
20
|
+
maxHeight: number;
|
|
21
|
+
realHeight: number;
|
|
22
|
+
contentHeight: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface PopupLocaltion {
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
top: number;
|
|
29
|
+
left: number;
|
|
30
|
+
padding: { top: number; right: number; bottom: number; left: number };
|
|
31
|
+
border: { top: number; right: number; bottom: number; left: number };
|
|
32
|
+
}
|