selective-ui 1.4.0 → 1.4.2
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 +2 -2
- package/dist/selective-ui.css.map +1 -1
- package/dist/selective-ui.esm.js +407 -573
- 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 +409 -575
- package/dist/selective-ui.umd.js.map +1 -1
- package/package.json +12 -12
- package/src/css/views/option-view.css +2 -2
- package/src/ts/adapter/mixed-adapter.ts +149 -71
- 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 +260 -84
- package/src/ts/core/base/adapter.ts +61 -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 +178 -45
- 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 +88 -20
- 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 +14 -4
- 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
|
@@ -62,9 +62,12 @@ import { LifecycleState } from "src/ts/types/core/base/lifecycle.type";
|
|
|
62
62
|
* @see {@link ModelContract}
|
|
63
63
|
*/
|
|
64
64
|
export class Adapter<
|
|
65
|
-
TItem extends ModelContract<any, any> & { view
|
|
66
|
-
TViewer extends ViewContract<any
|
|
67
|
-
>
|
|
65
|
+
TItem extends ModelContract<any, any> & { view?: TViewer; isInit: boolean },
|
|
66
|
+
TViewer extends ViewContract<any>,
|
|
67
|
+
>
|
|
68
|
+
extends Lifecycle
|
|
69
|
+
implements AdapterContract<TItem>
|
|
70
|
+
{
|
|
68
71
|
/**
|
|
69
72
|
* Current list of items managed by the adapter.
|
|
70
73
|
*
|
|
@@ -92,6 +95,17 @@ export class Adapter<
|
|
|
92
95
|
*/
|
|
93
96
|
recyclerView: any;
|
|
94
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Tracks all scheduler keys registered by this adapter instance via
|
|
100
|
+
* {@link onPropChanging} and {@link onPropChanged}.
|
|
101
|
+
*
|
|
102
|
+
* Used during {@link destroy} to clean up all associated pipelines
|
|
103
|
+
* from the global {@link Libs.callbackScheduler}.
|
|
104
|
+
*
|
|
105
|
+
* Keys are deduplicated automatically by Set semantics.
|
|
106
|
+
*/
|
|
107
|
+
callbackSchedulerList: Set<string> = new Set();
|
|
108
|
+
|
|
95
109
|
/**
|
|
96
110
|
* Creates an adapter with an optional initial item list and initializes its lifecycle.
|
|
97
111
|
*
|
|
@@ -118,7 +132,11 @@ export class Adapter<
|
|
|
118
132
|
* @param {number} position - Index of the item within the adapter item list.
|
|
119
133
|
* @returns {void}
|
|
120
134
|
*/
|
|
121
|
-
public onViewHolder(
|
|
135
|
+
public onViewHolder(
|
|
136
|
+
item: TItem,
|
|
137
|
+
viewer?: TViewer,
|
|
138
|
+
position?: number,
|
|
139
|
+
): void {
|
|
122
140
|
void position;
|
|
123
141
|
|
|
124
142
|
const v = viewer;
|
|
@@ -142,8 +160,17 @@ export class Adapter<
|
|
|
142
160
|
* @returns {void}
|
|
143
161
|
* @see {@link changingProp}
|
|
144
162
|
*/
|
|
145
|
-
public onPropChanging(
|
|
146
|
-
|
|
163
|
+
public onPropChanging(
|
|
164
|
+
propName: string,
|
|
165
|
+
callback: (...args: unknown[]) => void,
|
|
166
|
+
): void {
|
|
167
|
+
const key = `${propName}ing_${this.adapterKey}`;
|
|
168
|
+
Libs.callbackScheduler.on(
|
|
169
|
+
key,
|
|
170
|
+
callback,
|
|
171
|
+
{ debounce: 0 },
|
|
172
|
+
);
|
|
173
|
+
this.callbackSchedulerList.add(key);
|
|
147
174
|
}
|
|
148
175
|
|
|
149
176
|
/**
|
|
@@ -159,8 +186,15 @@ export class Adapter<
|
|
|
159
186
|
* @returns {void}
|
|
160
187
|
* @see {@link changeProp}
|
|
161
188
|
*/
|
|
162
|
-
public onPropChanged(
|
|
163
|
-
|
|
189
|
+
public onPropChanged(
|
|
190
|
+
propName: string,
|
|
191
|
+
callback: (...args: unknown[]) => void,
|
|
192
|
+
): void {
|
|
193
|
+
const key = `${propName}_${this.adapterKey}`;
|
|
194
|
+
Libs.callbackScheduler.on(key, callback, {
|
|
195
|
+
debounce: 0,
|
|
196
|
+
});
|
|
197
|
+
this.callbackSchedulerList.add(key);
|
|
164
198
|
}
|
|
165
199
|
|
|
166
200
|
/**
|
|
@@ -174,7 +208,10 @@ export class Adapter<
|
|
|
174
208
|
* @returns {Promise<void>} Resolves when scheduled callbacks complete.
|
|
175
209
|
*/
|
|
176
210
|
public changeProp(propName: string, ...params: unknown[]): Promise<void> {
|
|
177
|
-
return Libs.callbackScheduler.run(
|
|
211
|
+
return Libs.callbackScheduler.run(
|
|
212
|
+
`${propName}_${this.adapterKey}`,
|
|
213
|
+
...params,
|
|
214
|
+
);
|
|
178
215
|
}
|
|
179
216
|
|
|
180
217
|
/**
|
|
@@ -188,7 +225,10 @@ export class Adapter<
|
|
|
188
225
|
* @returns {Promise<void>} Resolves when scheduled callbacks complete.
|
|
189
226
|
*/
|
|
190
227
|
public changingProp(propName: string, ...params: unknown[]): Promise<void> {
|
|
191
|
-
return Libs.callbackScheduler.run(
|
|
228
|
+
return Libs.callbackScheduler.run(
|
|
229
|
+
`${propName}ing_${this.adapterKey}`,
|
|
230
|
+
...params,
|
|
231
|
+
);
|
|
192
232
|
}
|
|
193
233
|
|
|
194
234
|
/**
|
|
@@ -198,9 +238,9 @@ export class Adapter<
|
|
|
198
238
|
*
|
|
199
239
|
* @param {HTMLElement} parent - Container element that will host the viewer.
|
|
200
240
|
* @param {TItem} item - The model for which the viewer is created.
|
|
201
|
-
* @returns {TViewer
|
|
241
|
+
* @returns {TViewer} The created viewer instance; `null` by default.
|
|
202
242
|
*/
|
|
203
|
-
public viewHolder(parent: HTMLElement, item: TItem): TViewer
|
|
243
|
+
public viewHolder?(parent: HTMLElement, item: TItem): TViewer {
|
|
204
244
|
void parent;
|
|
205
245
|
void item;
|
|
206
246
|
return null;
|
|
@@ -316,10 +356,17 @@ export class Adapter<
|
|
|
316
356
|
return;
|
|
317
357
|
}
|
|
318
358
|
|
|
359
|
+
this.callbackSchedulerList.forEach((key) => {
|
|
360
|
+
Libs.callbackScheduler.off(key);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
this.callbackSchedulerList.clear();
|
|
319
364
|
this.recyclerView = null;
|
|
320
|
-
this.items.forEach(item => {
|
|
365
|
+
this.items.forEach((item) => {
|
|
321
366
|
item?.destroy?.();
|
|
322
367
|
});
|
|
323
368
|
this.items = [];
|
|
369
|
+
|
|
370
|
+
super.destroy();
|
|
324
371
|
}
|
|
325
|
-
}
|
|
372
|
+
}
|
|
@@ -131,7 +131,8 @@ export class Fenwick extends Lifecycle {
|
|
|
131
131
|
* Returns 0 if the first element already exceeds `target`.
|
|
132
132
|
*/
|
|
133
133
|
public lowerBoundPrefix(target: number): number {
|
|
134
|
-
let idx = 0,
|
|
134
|
+
let idx = 0,
|
|
135
|
+
bitMask = 1;
|
|
135
136
|
while (bitMask << 1 <= this.stackNum) bitMask <<= 1;
|
|
136
137
|
|
|
137
138
|
let cur = 0;
|
|
@@ -144,4 +145,4 @@ export class Fenwick extends Lifecycle {
|
|
|
144
145
|
}
|
|
145
146
|
return idx;
|
|
146
147
|
}
|
|
147
|
-
}
|
|
148
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
LifecycleHookContext,
|
|
3
|
+
LifecycleHooks,
|
|
4
|
+
LifecycleState,
|
|
5
|
+
} from "src/ts/types/core/base/lifecycle.type";
|
|
2
6
|
|
|
3
7
|
type LifecycleHookName = keyof LifecycleHooks;
|
|
4
8
|
|
|
@@ -59,7 +63,10 @@ export class Lifecycle {
|
|
|
59
63
|
* This map is initialized with keys for all supported hooks in the constructor.
|
|
60
64
|
* Callbacks are cleared on {@link destroy}.
|
|
61
65
|
*/
|
|
62
|
-
private hooks: Map<
|
|
66
|
+
private hooks: Map<
|
|
67
|
+
LifecycleHookName,
|
|
68
|
+
Set<(ctx: LifecycleHookContext) => void>
|
|
69
|
+
> = new Map();
|
|
63
70
|
|
|
64
71
|
/**
|
|
65
72
|
* Constructs the lifecycle manager and pre-registers hook containers.
|
|
@@ -98,7 +105,10 @@ export class Lifecycle {
|
|
|
98
105
|
* @param {(ctx: LifecycleHookContext) => void} fn - Callback to remove.
|
|
99
106
|
* @returns {this} The current instance (chainable).
|
|
100
107
|
*/
|
|
101
|
-
off(
|
|
108
|
+
off(
|
|
109
|
+
hook: LifecycleHookName,
|
|
110
|
+
fn: (ctx: LifecycleHookContext) => void,
|
|
111
|
+
): this {
|
|
102
112
|
this.hooks.get(hook)!.delete(fn);
|
|
103
113
|
return this;
|
|
104
114
|
}
|
|
@@ -255,4 +265,4 @@ export class Lifecycle {
|
|
|
255
265
|
set.clear();
|
|
256
266
|
}
|
|
257
267
|
}
|
|
258
|
-
}
|
|
268
|
+
}
|
|
@@ -43,16 +43,18 @@ export class Model<
|
|
|
43
43
|
TTarget extends HTMLElement,
|
|
44
44
|
TTags extends Record<string, HTMLElement>,
|
|
45
45
|
TView extends ViewContract<TTags>,
|
|
46
|
-
TOptions = unknown
|
|
47
|
-
>
|
|
48
|
-
|
|
46
|
+
TOptions = unknown,
|
|
47
|
+
>
|
|
48
|
+
extends Lifecycle
|
|
49
|
+
implements ModelContract<TTarget, TView>
|
|
50
|
+
{
|
|
49
51
|
/**
|
|
50
52
|
* The currently bound target DOM element.
|
|
51
53
|
*
|
|
52
54
|
* This element typically represents the source-of-truth node in the host DOM (e.g., a native `<option>`).
|
|
53
55
|
* May be replaced via {@link updateTarget} during reconciliation.
|
|
54
56
|
*/
|
|
55
|
-
public targetElement
|
|
57
|
+
public targetElement?: TTarget;
|
|
56
58
|
|
|
57
59
|
/**
|
|
58
60
|
* Configuration options supplied at construction time.
|
|
@@ -66,25 +68,25 @@ export class Model<
|
|
|
66
68
|
* Ownership: this model will destroy the view on {@link destroy}.
|
|
67
69
|
* The view may be attached/assigned by external orchestrators (Adapter/RecyclerView) after construction.
|
|
68
70
|
*/
|
|
69
|
-
public view
|
|
71
|
+
public view?: TView;
|
|
70
72
|
|
|
71
73
|
/**
|
|
72
74
|
* Position index used by list infrastructure for ordering/tracking.
|
|
73
75
|
* Semantics are library-specific (e.g., top-level index or adapter position).
|
|
74
76
|
*/
|
|
75
|
-
public position = -1;
|
|
77
|
+
public position: number = -1;
|
|
76
78
|
|
|
77
79
|
/**
|
|
78
80
|
* Indicates whether this model has completed its initial binding step.
|
|
79
81
|
* Typically set by the adapter/view binding layer to prevent duplicate listener wiring.
|
|
80
82
|
*/
|
|
81
|
-
public isInit = false;
|
|
83
|
+
public isInit: boolean = false;
|
|
82
84
|
|
|
83
85
|
/**
|
|
84
86
|
* Indicates whether this model has been removed/destroyed from the active dataset.
|
|
85
87
|
* Set to `true` during {@link destroy}.
|
|
86
88
|
*/
|
|
87
|
-
public isRemoved = false;
|
|
89
|
+
public isRemoved: boolean = false;
|
|
88
90
|
|
|
89
91
|
/**
|
|
90
92
|
* Returns the current "value" associated with the bound target element.
|
|
@@ -107,13 +109,13 @@ export class Model<
|
|
|
107
109
|
* - Calls {@link Lifecycle.init} immediately (`NEW → INITIALIZED`).
|
|
108
110
|
*
|
|
109
111
|
* @param {TOptions} options - Configuration options for the model.
|
|
110
|
-
* @param {TTarget
|
|
111
|
-
* @param {TView
|
|
112
|
+
* @param {TTarget} [targetElement=null] - Optional DOM element to bind.
|
|
113
|
+
* @param {TView} [view=null] - Optional view responsible for rendering this model.
|
|
112
114
|
*/
|
|
113
115
|
public constructor(
|
|
114
116
|
options: TOptions,
|
|
115
|
-
targetElement
|
|
116
|
-
view
|
|
117
|
+
targetElement?: TTarget,
|
|
118
|
+
view?: TView,
|
|
117
119
|
) {
|
|
118
120
|
super();
|
|
119
121
|
this.options = options;
|
|
@@ -134,10 +136,10 @@ export class Model<
|
|
|
134
136
|
* - Assigns {@link targetElement}.
|
|
135
137
|
* - Calls {@link Lifecycle.update} (guarded by lifecycle state).
|
|
136
138
|
*
|
|
137
|
-
* @param {TTarget
|
|
139
|
+
* @param {TTarget} targetElement - The new DOM element to associate with this model.
|
|
138
140
|
* @returns {void}
|
|
139
141
|
*/
|
|
140
|
-
public updateTarget(targetElement
|
|
142
|
+
public updateTarget(targetElement?: TTarget): void {
|
|
141
143
|
this.targetElement = targetElement;
|
|
142
144
|
this.update();
|
|
143
145
|
}
|
|
@@ -167,4 +169,4 @@ export class Model<
|
|
|
167
169
|
|
|
168
170
|
super.destroy();
|
|
169
171
|
}
|
|
170
|
-
}
|
|
172
|
+
}
|
|
@@ -22,9 +22,11 @@ import { LifecycleState } from "src/ts/types/core/base/lifecycle.type";
|
|
|
22
22
|
*/
|
|
23
23
|
export class RecyclerView<
|
|
24
24
|
TItem extends ModelContract<any, any>,
|
|
25
|
-
TAdapter extends AdapterContract<TItem
|
|
26
|
-
>
|
|
27
|
-
|
|
25
|
+
TAdapter extends AdapterContract<TItem>,
|
|
26
|
+
>
|
|
27
|
+
extends Lifecycle
|
|
28
|
+
implements RecyclerViewContract<TAdapter>
|
|
29
|
+
{
|
|
28
30
|
/** Root container that hosts rendered item views. */
|
|
29
31
|
public viewElement: HTMLDivElement | null = null;
|
|
30
32
|
|
|
@@ -113,10 +115,10 @@ export class RecyclerView<
|
|
|
113
115
|
if (this.is(LifecycleState.DESTROYED)) {
|
|
114
116
|
return;
|
|
115
117
|
}
|
|
116
|
-
|
|
118
|
+
|
|
117
119
|
this.viewElement = null;
|
|
118
120
|
this.adapter = null;
|
|
119
121
|
|
|
120
122
|
super.destroy();
|
|
121
123
|
}
|
|
122
|
-
}
|
|
124
|
+
}
|
package/src/ts/core/base/view.ts
CHANGED
|
@@ -39,13 +39,16 @@ import { LifecycleState } from "src/ts/types/core/base/lifecycle.type";
|
|
|
39
39
|
* @see {@link ViewContract}
|
|
40
40
|
* @see {@link LifecycleState}
|
|
41
41
|
*/
|
|
42
|
-
export class View<TTags extends Record<string, HTMLElement>>
|
|
42
|
+
export class View<TTags extends Record<string, HTMLElement>>
|
|
43
|
+
extends Lifecycle
|
|
44
|
+
implements ViewContract<TTags>
|
|
45
|
+
{
|
|
43
46
|
/**
|
|
44
47
|
* Host container element into which this view's root element is rendered/attached.
|
|
45
48
|
*
|
|
46
49
|
* This reference is captured at construction time and cleared on {@link destroy}.
|
|
47
50
|
*/
|
|
48
|
-
public parent
|
|
51
|
+
public parent?: HTMLElement;
|
|
49
52
|
|
|
50
53
|
/**
|
|
51
54
|
* Mounted view result containing:
|
|
@@ -54,7 +57,7 @@ export class View<TTags extends Record<string, HTMLElement>> extends Lifecycle i
|
|
|
54
57
|
*
|
|
55
58
|
* This is expected to be assigned by subclasses (or a mount helper) before {@link getView} is called.
|
|
56
59
|
*/
|
|
57
|
-
public view
|
|
60
|
+
public view?: MountViewResult<TTags>;
|
|
58
61
|
|
|
59
62
|
/**
|
|
60
63
|
* Creates a View bound to the specified parent container and initializes lifecycle state.
|
|
@@ -79,7 +82,9 @@ export class View<TTags extends Record<string, HTMLElement>> extends Lifecycle i
|
|
|
79
82
|
*/
|
|
80
83
|
public getView(): HTMLElement {
|
|
81
84
|
if (!this.view?.view) {
|
|
82
|
-
throw new Error(
|
|
85
|
+
throw new Error(
|
|
86
|
+
"View is not mounted. Did you forget to set this.view?",
|
|
87
|
+
);
|
|
83
88
|
}
|
|
84
89
|
return this.view.view;
|
|
85
90
|
}
|
|
@@ -108,4 +113,4 @@ export class View<TTags extends Record<string, HTMLElement>> extends Lifecycle i
|
|
|
108
113
|
|
|
109
114
|
super.destroy();
|
|
110
115
|
}
|
|
111
|
-
}
|
|
116
|
+
}
|