selective-ui 1.2.0 → 1.2.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 +3 -1
- package/dist/selective-ui.css.map +1 -1
- package/dist/selective-ui.esm.js +487 -436
- 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 +488 -437
- package/dist/selective-ui.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/css/components/popup.css +3 -1
- package/src/ts/adapter/mixed-adapter.ts +56 -50
- package/src/ts/components/accessorybox.ts +49 -21
- package/src/ts/components/directive.ts +3 -3
- package/src/ts/components/empty-state.ts +7 -7
- package/src/ts/components/loading-state.ts +7 -7
- package/src/ts/components/option-handle.ts +17 -17
- package/src/ts/components/placeholder.ts +12 -12
- package/src/ts/components/popup.ts +93 -108
- package/src/ts/components/searchbox.ts +14 -14
- package/src/ts/components/selectbox.ts +41 -31
- package/src/ts/core/base/adapter.ts +12 -12
- package/src/ts/core/base/model.ts +12 -13
- package/src/ts/core/base/recyclerview.ts +7 -7
- package/src/ts/core/base/view.ts +6 -6
- package/src/ts/core/base/virtual-recyclerview.ts +51 -50
- package/src/ts/core/model-manager.ts +53 -53
- package/src/ts/core/search-controller.ts +70 -73
- package/src/ts/models/group-model.ts +21 -21
- package/src/ts/models/option-model.ts +50 -31
- package/src/ts/services/dataset-observer.ts +17 -17
- package/src/ts/services/ea-observer.ts +21 -21
- package/src/ts/services/effector.ts +30 -30
- package/src/ts/services/refresher.ts +1 -1
- package/src/ts/services/resize-observer.ts +29 -29
- package/src/ts/services/select-observer.ts +29 -29
- package/src/ts/types/components/popup.type.ts +15 -0
- package/src/ts/types/utils/istorage.type.ts +1 -1
- package/src/ts/utils/callback-scheduler.ts +4 -4
- package/src/ts/utils/ievents.ts +4 -4
- package/src/ts/utils/istorage.ts +5 -5
- package/src/ts/utils/libs.ts +38 -29
- package/src/ts/utils/selective.ts +11 -11
- package/src/ts/views/group-view.ts +7 -7
- package/src/ts/views/option-view.ts +51 -51
|
@@ -15,21 +15,21 @@ export class SearchBox {
|
|
|
15
15
|
if (options) this.init(options);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
nodeMounted: MountViewResult<SearchBoxTags> | null = null;
|
|
18
|
+
private nodeMounted: MountViewResult<SearchBoxTags> | null = null;
|
|
19
19
|
|
|
20
|
-
node: HTMLDivElement | null = null;
|
|
20
|
+
public node: HTMLDivElement | null = null;
|
|
21
21
|
|
|
22
|
-
SearchInput: HTMLInputElement | null = null;
|
|
22
|
+
private SearchInput: HTMLInputElement | null = null;
|
|
23
23
|
|
|
24
|
-
onSearch: SearchHandler | null = null;
|
|
24
|
+
public onSearch: SearchHandler | null = null;
|
|
25
25
|
|
|
26
|
-
options: SelectiveOptions | null = null;
|
|
26
|
+
private options: SelectiveOptions | null = null;
|
|
27
27
|
|
|
28
|
-
onNavigate: NavigateHandler | null = null;
|
|
28
|
+
public onNavigate: NavigateHandler | null = null;
|
|
29
29
|
|
|
30
|
-
onEnter: (() => void) | null = null;
|
|
30
|
+
public onEnter: (() => void) | null = null;
|
|
31
31
|
|
|
32
|
-
onEsc: (() => void) | null = null;
|
|
32
|
+
public onEsc: (() => void) | null = null;
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Initializes the search box DOM, sets ARIA attributes, and wires keyboard/mouse/input events.
|
|
@@ -37,7 +37,7 @@ export class SearchBox {
|
|
|
37
37
|
*
|
|
38
38
|
* @param {object} options - Configuration including placeholder and SEID_LIST for aria-controls.
|
|
39
39
|
*/
|
|
40
|
-
init(options: SelectiveOptions): void {
|
|
40
|
+
private init(options: SelectiveOptions): void {
|
|
41
41
|
this.nodeMounted = Libs.mountNode({
|
|
42
42
|
SearchBox: {
|
|
43
43
|
tag: { node: "div", classList: ["selective-ui-searchbox", "hide"] },
|
|
@@ -110,7 +110,7 @@ export class SearchBox {
|
|
|
110
110
|
* Shows the search box, toggles read-only based on `options.searchable`,
|
|
111
111
|
* and focuses the input when searchable.
|
|
112
112
|
*/
|
|
113
|
-
show(): void {
|
|
113
|
+
public show(): void {
|
|
114
114
|
if (!this.node || !this.SearchInput || !this.options) return;
|
|
115
115
|
|
|
116
116
|
this.node.classList.remove("hide");
|
|
@@ -126,7 +126,7 @@ export class SearchBox {
|
|
|
126
126
|
/**
|
|
127
127
|
* Hides the search box by adding the "hide" class.
|
|
128
128
|
*/
|
|
129
|
-
hide(): void {
|
|
129
|
+
public hide(): void {
|
|
130
130
|
if (!this.node) return;
|
|
131
131
|
this.node.classList.add("hide");
|
|
132
132
|
}
|
|
@@ -136,7 +136,7 @@ export class SearchBox {
|
|
|
136
136
|
*
|
|
137
137
|
* @param {boolean} [isTrigger=true] - Whether to invoke onSearch with an empty string.
|
|
138
138
|
*/
|
|
139
|
-
clear(isTrigger: boolean = true): void {
|
|
139
|
+
public clear(isTrigger: boolean = true): void {
|
|
140
140
|
if (!this.nodeMounted) return;
|
|
141
141
|
this.nodeMounted.tags.SearchInput.value = "";
|
|
142
142
|
this.onSearch?.("", isTrigger);
|
|
@@ -147,7 +147,7 @@ export class SearchBox {
|
|
|
147
147
|
*
|
|
148
148
|
* @param {string} value - The new placeholder text.
|
|
149
149
|
*/
|
|
150
|
-
setPlaceHolder(value: string): void {
|
|
150
|
+
public setPlaceHolder(value: string): void {
|
|
151
151
|
if (!this.SearchInput) return;
|
|
152
152
|
this.SearchInput.placeholder = Libs.stripHtml(value);
|
|
153
153
|
}
|
|
@@ -157,7 +157,7 @@ export class SearchBox {
|
|
|
157
157
|
*
|
|
158
158
|
* @param {string} id - The DOM id of the active option element.
|
|
159
159
|
*/
|
|
160
|
-
setActiveDescendant(id: string): void {
|
|
160
|
+
public setActiveDescendant(id: string): void {
|
|
161
161
|
if (!this.SearchInput) return;
|
|
162
162
|
this.SearchInput.setAttribute("aria-activedescendant", id);
|
|
163
163
|
}
|
|
@@ -37,35 +37,37 @@ export class SelectBox {
|
|
|
37
37
|
* @param {HTMLSelectElement|null} [select=null] - The native select element to enhance.
|
|
38
38
|
* @param {any|null} [Selective=null] - The Selective framework/context used for configuration and services.
|
|
39
39
|
*/
|
|
40
|
-
constructor(select: HTMLSelectElement | null = null, Selective: any | null = null) {
|
|
40
|
+
public constructor(select: HTMLSelectElement | null = null, Selective: any | null = null) {
|
|
41
41
|
if (select) this.init(select, Selective);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
container: Partial<ContainerRuntime> = {};
|
|
44
|
+
public container: Partial<ContainerRuntime> = {};
|
|
45
45
|
|
|
46
|
-
oldValue: unknown = null;
|
|
46
|
+
private oldValue: unknown = null;
|
|
47
47
|
|
|
48
|
-
node: HTMLDivElement | null = null;
|
|
48
|
+
private node: HTMLDivElement | null = null;
|
|
49
49
|
|
|
50
|
-
options: SelectiveOptions | null = null;
|
|
50
|
+
private options: SelectiveOptions | null = null;
|
|
51
51
|
|
|
52
|
-
optionModelManager: ModelManager<MixedItem, MixedAdapter> | null = null;
|
|
52
|
+
private optionModelManager: ModelManager<MixedItem, MixedAdapter> | null = null;
|
|
53
53
|
|
|
54
|
-
isOpen = false;
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
private isOpen = false;
|
|
55
|
+
|
|
56
|
+
private hasLoadedOnce = false;
|
|
57
|
+
|
|
58
|
+
private isBeforeSearch = false;
|
|
57
59
|
|
|
58
60
|
/** Selective context (global helper) */
|
|
59
|
-
Selective: Selective | null = null;
|
|
61
|
+
public Selective: Selective | null = null;
|
|
60
62
|
|
|
61
63
|
/**
|
|
62
64
|
* Gets or sets the disabled state of the SelectBox.
|
|
63
65
|
* When set, updates CSS class and ARIA attributes to reflect the disabled state.
|
|
64
66
|
*/
|
|
65
|
-
get isDisabled(): boolean {
|
|
67
|
+
public get isDisabled(): boolean {
|
|
66
68
|
return !!this.options?.disabled;
|
|
67
69
|
}
|
|
68
|
-
set isDisabled(value: boolean) {
|
|
70
|
+
public set isDisabled(value: boolean) {
|
|
69
71
|
if (!this.options || !this.node) return;
|
|
70
72
|
this.options.disabled = value;
|
|
71
73
|
this.node.classList.toggle("disabled", value);
|
|
@@ -77,10 +79,10 @@ export class SelectBox {
|
|
|
77
79
|
* Gets or sets the read-only state of the SelectBox.
|
|
78
80
|
* When set, toggles the "readonly" CSS class to prevent user interaction.
|
|
79
81
|
*/
|
|
80
|
-
get isReadOnly(): boolean {
|
|
82
|
+
public get isReadOnly(): boolean {
|
|
81
83
|
return !!this.options?.readonly;
|
|
82
84
|
}
|
|
83
|
-
set isReadOnly(value: boolean) {
|
|
85
|
+
public set isReadOnly(value: boolean) {
|
|
84
86
|
if (!this.options || !this.node) return;
|
|
85
87
|
this.options.readonly = value;
|
|
86
88
|
this.node.classList.toggle("readonly", value);
|
|
@@ -90,10 +92,10 @@ export class SelectBox {
|
|
|
90
92
|
* Gets or sets the visibility state of the SelectBox.
|
|
91
93
|
* When set, toggles the "invisible" CSS class to show or hide the component.
|
|
92
94
|
*/
|
|
93
|
-
get isVisible(): boolean {
|
|
95
|
+
public get isVisible(): boolean {
|
|
94
96
|
return !!this.options?.visible;
|
|
95
97
|
}
|
|
96
|
-
set isVisible(value: boolean) {
|
|
98
|
+
public set isVisible(value: boolean) {
|
|
97
99
|
if (!this.options || !this.node) return;
|
|
98
100
|
this.options.visible = value;
|
|
99
101
|
this.node.classList.toggle("invisible", !value);
|
|
@@ -105,7 +107,7 @@ export class SelectBox {
|
|
|
105
107
|
* @param {HTMLSelectElement} select - The native <select> element to enhance.
|
|
106
108
|
* @param {any} Selective - The Selective framework/context for services and configuration.
|
|
107
109
|
*/
|
|
108
|
-
init(select: HTMLSelectElement, Selective: any): void {
|
|
110
|
+
private init(select: HTMLSelectElement, Selective: any): void {
|
|
109
111
|
const bindedMap = Libs.getBinderMap(select) as BinderMap;
|
|
110
112
|
const options = bindedMap.options as SelectiveOptions;
|
|
111
113
|
|
|
@@ -251,6 +253,7 @@ export class SelectBox {
|
|
|
251
253
|
}
|
|
252
254
|
|
|
253
255
|
const optionAdapter = container.popup!.optionAdapter as MixedAdapter;
|
|
256
|
+
let hightlightTimer : ReturnType<typeof setTimeout> | null = null;
|
|
254
257
|
|
|
255
258
|
const searchHandle = (keyword: string, isTrigger: boolean) => {
|
|
256
259
|
if (!isTrigger && keyword === "") {
|
|
@@ -261,13 +264,18 @@ export class SelectBox {
|
|
|
261
264
|
searchController
|
|
262
265
|
.search(keyword)
|
|
263
266
|
.then((result: any) => {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
267
|
+
clearTimeout(hightlightTimer!);
|
|
268
|
+
Libs.callbackScheduler.clear(`sche_vis_proxy_${optionAdapter.adapterKey}`);
|
|
269
|
+
Libs.callbackScheduler.on(`sche_vis_proxy_${optionAdapter.adapterKey}`, () => {
|
|
270
|
+
container.popup?.triggerResize?.();
|
|
271
|
+
|
|
272
|
+
if (result?.hasResults) {
|
|
273
|
+
hightlightTimer = setTimeout(() => {
|
|
274
|
+
optionAdapter.resetHighlight();
|
|
275
|
+
container.popup?.triggerResize?.();
|
|
276
|
+
}, options.animationtime ?? 0);
|
|
277
|
+
}
|
|
278
|
+
}, { debounce: 10 });
|
|
271
279
|
})
|
|
272
280
|
.catch((error: unknown) => {
|
|
273
281
|
console.error("Search error:", error);
|
|
@@ -279,15 +287,17 @@ export class SelectBox {
|
|
|
279
287
|
|
|
280
288
|
searchbox.onSearch = (keyword: string, isTrigger: boolean) => {
|
|
281
289
|
if (!searchController.compareSearchTrigger(keyword)) return;
|
|
290
|
+
if (searchHandleTimer) clearTimeout(searchHandleTimer);
|
|
282
291
|
|
|
283
292
|
if (searchController.isAjax()) {
|
|
284
|
-
if (searchHandleTimer) clearTimeout(searchHandleTimer);
|
|
285
293
|
container.popup?.showLoading?.();
|
|
286
294
|
searchHandleTimer = setTimeout(() => {
|
|
287
295
|
searchHandle(keyword, isTrigger);
|
|
288
296
|
}, options.delaysearchtime ?? 0);
|
|
289
297
|
} else {
|
|
290
|
-
|
|
298
|
+
searchHandleTimer = setTimeout(() => {
|
|
299
|
+
searchHandle(keyword, isTrigger);
|
|
300
|
+
}, 10);
|
|
291
301
|
}
|
|
292
302
|
};
|
|
293
303
|
|
|
@@ -320,7 +330,7 @@ export class SelectBox {
|
|
|
320
330
|
/**
|
|
321
331
|
* Disconnects observers associated with the SelectBox instance.
|
|
322
332
|
*/
|
|
323
|
-
deInit(): void {
|
|
333
|
+
public deInit(): void {
|
|
324
334
|
const c: any = this.container ?? {};
|
|
325
335
|
const { selectObserver, datasetObserver } = c;
|
|
326
336
|
|
|
@@ -331,7 +341,7 @@ export class SelectBox {
|
|
|
331
341
|
/**
|
|
332
342
|
* Returns an action API for controlling the SelectBox instance.
|
|
333
343
|
*/
|
|
334
|
-
getAction(): SelectBoxAction | null {
|
|
344
|
+
public getAction(): SelectBoxAction | null {
|
|
335
345
|
const container = this.container;
|
|
336
346
|
const superThis = this;
|
|
337
347
|
const getInstance = () => {
|
|
@@ -717,7 +727,7 @@ export class SelectBox {
|
|
|
717
727
|
/**
|
|
718
728
|
* Creates a property on the given object with custom getter and setter behavior.
|
|
719
729
|
*/
|
|
720
|
-
createSymProp(
|
|
730
|
+
private createSymProp(
|
|
721
731
|
obj: Record<string, any>,
|
|
722
732
|
prop: "disabled" | "readonly" | "visible",
|
|
723
733
|
privateProp: "isDisabled" | "isReadOnly" | "isVisible"
|
|
@@ -742,7 +752,7 @@ export class SelectBox {
|
|
|
742
752
|
/**
|
|
743
753
|
* Flattens and returns all option models from the current resources.
|
|
744
754
|
*/
|
|
745
|
-
getModelOption(isSelected: boolean | null = null): OptionModel[] {
|
|
755
|
+
private getModelOption(isSelected: boolean | null = null): OptionModel[] {
|
|
746
756
|
if (!this.optionModelManager) return [];
|
|
747
757
|
|
|
748
758
|
const { modelList } = this.optionModelManager.getResources();
|
|
@@ -764,7 +774,7 @@ export class SelectBox {
|
|
|
764
774
|
return flatOptions;
|
|
765
775
|
}
|
|
766
776
|
|
|
767
|
-
detroy() {
|
|
777
|
+
public detroy() {
|
|
768
778
|
this.container.popup!.detroy();
|
|
769
779
|
}
|
|
770
780
|
}
|
|
@@ -35,7 +35,7 @@ export class Adapter<
|
|
|
35
35
|
* Lifecycle hook called once after construction. Override in subclasses to
|
|
36
36
|
* perform setup tasks (e.g., event wiring, cache building).
|
|
37
37
|
*/
|
|
38
|
-
onInit(): void { }
|
|
38
|
+
public onInit(): void { }
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Binds an item model to its viewer at a given position. If the item has not
|
|
@@ -45,7 +45,7 @@ export class Adapter<
|
|
|
45
45
|
* @param {TViewer|null} viewer - The view instance responsible for rendering the model.
|
|
46
46
|
* @param {number} position - The index of the item within the adapter.
|
|
47
47
|
*/
|
|
48
|
-
onViewHolder(item: TItem, viewer: TViewer | null, position: number): void {
|
|
48
|
+
public onViewHolder(item: TItem, viewer: TViewer | null, position: number): void {
|
|
49
49
|
void position;
|
|
50
50
|
|
|
51
51
|
const v = viewer;
|
|
@@ -63,7 +63,7 @@ export class Adapter<
|
|
|
63
63
|
* @param {string} propName - The property name to observe (e.g., "items").
|
|
64
64
|
* @param {Function} callback - Function to execute before the property changes.
|
|
65
65
|
*/
|
|
66
|
-
onPropChanging(propName: string, callback: (...args: unknown[]) => void): void {
|
|
66
|
+
public onPropChanging(propName: string, callback: (...args: unknown[]) => void): void {
|
|
67
67
|
Libs.callbackScheduler.on(`${propName}ing_${this.adapterKey}`, callback, { debounce: 1 });
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -74,7 +74,7 @@ export class Adapter<
|
|
|
74
74
|
* @param {string} propName - The property name to observe (e.g., "items").
|
|
75
75
|
* @param {Function} callback - Function to execute after the property changes.
|
|
76
76
|
*/
|
|
77
|
-
onPropChanged(propName: string, callback: (...args: unknown[]) => void): void {
|
|
77
|
+
public onPropChanged(propName: string, callback: (...args: unknown[]) => void): void {
|
|
78
78
|
Libs.callbackScheduler.on(`${propName}_${this.adapterKey}`, callback);
|
|
79
79
|
}
|
|
80
80
|
|
|
@@ -85,7 +85,7 @@ export class Adapter<
|
|
|
85
85
|
* @param {string} propName - The property name to emit (e.g., "items").
|
|
86
86
|
* @param {...any} params - Parameters forwarded to the callbacks.
|
|
87
87
|
*/
|
|
88
|
-
changeProp(propName: string, ...params: unknown[]): void {
|
|
88
|
+
public changeProp(propName: string, ...params: unknown[]): void {
|
|
89
89
|
Libs.callbackScheduler.run(`${propName}_${this.adapterKey}`, ...params);
|
|
90
90
|
}
|
|
91
91
|
|
|
@@ -96,7 +96,7 @@ export class Adapter<
|
|
|
96
96
|
* @param {string} propName - The property name to emit (e.g., "items").
|
|
97
97
|
* @param {...any} params - Parameters forwarded to the callbacks.
|
|
98
98
|
*/
|
|
99
|
-
changingProp(propName: string, ...params: unknown[]): void {
|
|
99
|
+
public changingProp(propName: string, ...params: unknown[]): void {
|
|
100
100
|
Libs.callbackScheduler.run(`${propName}ing_${this.adapterKey}`, ...params);
|
|
101
101
|
}
|
|
102
102
|
|
|
@@ -108,7 +108,7 @@ export class Adapter<
|
|
|
108
108
|
* @param {TItem} item - The model instance for which the viewer is created.
|
|
109
109
|
* @returns {TViewer|null} - The created viewer instance; null by default.
|
|
110
110
|
*/
|
|
111
|
-
viewHolder(parent: HTMLElement, item: TItem): TViewer | null {
|
|
111
|
+
public viewHolder(parent: HTMLElement, item: TItem): TViewer | null {
|
|
112
112
|
void parent;
|
|
113
113
|
void item;
|
|
114
114
|
return null;
|
|
@@ -119,7 +119,7 @@ export class Adapter<
|
|
|
119
119
|
*
|
|
120
120
|
* @returns {number} - The item count.
|
|
121
121
|
*/
|
|
122
|
-
itemCount(): number {
|
|
122
|
+
public itemCount(): number {
|
|
123
123
|
return this.items.length;
|
|
124
124
|
}
|
|
125
125
|
|
|
@@ -129,7 +129,7 @@ export class Adapter<
|
|
|
129
129
|
*
|
|
130
130
|
* @param {TItem[]} items - The new list of items to set.
|
|
131
131
|
*/
|
|
132
|
-
setItems(items: TItem[]): void {
|
|
132
|
+
public setItems(items: TItem[]): void {
|
|
133
133
|
this.changingProp("items", items);
|
|
134
134
|
this.items = items;
|
|
135
135
|
this.changeProp("items", items);
|
|
@@ -141,7 +141,7 @@ export class Adapter<
|
|
|
141
141
|
*
|
|
142
142
|
* @param {TItem[]} items - The source list of items to synchronize.
|
|
143
143
|
*/
|
|
144
|
-
syncFromSource(items: TItem[]): void {
|
|
144
|
+
public syncFromSource(items: TItem[]): void {
|
|
145
145
|
this.setItems(items);
|
|
146
146
|
}
|
|
147
147
|
|
|
@@ -151,7 +151,7 @@ export class Adapter<
|
|
|
151
151
|
*
|
|
152
152
|
* @param {HTMLElement} parent - The container element in which item viewers are rendered.
|
|
153
153
|
*/
|
|
154
|
-
updateRecyclerView(parent: HTMLElement): void {
|
|
154
|
+
public updateRecyclerView(parent: HTMLElement): void {
|
|
155
155
|
for (let index = 0; index < this.itemCount(); index++) {
|
|
156
156
|
const item = this.items[index];
|
|
157
157
|
|
|
@@ -172,7 +172,7 @@ export class Adapter<
|
|
|
172
172
|
*
|
|
173
173
|
* @param {TItem[]} items - The incoming data to apply to the adapter.
|
|
174
174
|
*/
|
|
175
|
-
updateData(items: TItem[]): void {
|
|
175
|
+
public updateData(items: TItem[]): void {
|
|
176
176
|
void items;
|
|
177
177
|
}
|
|
178
178
|
}
|
|
@@ -13,23 +13,22 @@ export class Model<
|
|
|
13
13
|
TView extends ViewContract<TTags>,
|
|
14
14
|
TOptions = unknown
|
|
15
15
|
> implements ModelContract<TTarget, TView> {
|
|
16
|
-
targetElement: TTarget | null = null;
|
|
16
|
+
public targetElement: TTarget | null = null;
|
|
17
17
|
|
|
18
|
-
options: TOptions;
|
|
18
|
+
public options: TOptions;
|
|
19
19
|
|
|
20
|
-
view: TView | null = null;
|
|
20
|
+
public view: TView | null = null;
|
|
21
21
|
|
|
22
|
-
position = -1;
|
|
22
|
+
public position = -1;
|
|
23
23
|
|
|
24
|
-
isInit = false;
|
|
25
|
-
|
|
26
|
-
isRemoved = false;
|
|
24
|
+
public isInit = false;
|
|
27
25
|
|
|
26
|
+
public isRemoved = false;
|
|
28
27
|
/**
|
|
29
28
|
* Returns the current value from the underlying target element's "value" attribute.
|
|
30
29
|
* For single-select, this is typically a string; for multi-select, may be an array depending on usage.
|
|
31
30
|
*/
|
|
32
|
-
get value(): string | null | string[] {
|
|
31
|
+
public get value(): string | null | string[] {
|
|
33
32
|
return this.targetElement?.getAttribute("value") ?? null;
|
|
34
33
|
}
|
|
35
34
|
|
|
@@ -41,7 +40,7 @@ export class Model<
|
|
|
41
40
|
* @param {TTarget|null} [targetElement=null] - The underlying element (e.g., <option> or group node).
|
|
42
41
|
* @param {TView|null} [view=null] - The associated view responsible for rendering the model.
|
|
43
42
|
*/
|
|
44
|
-
constructor(options: TOptions, targetElement: TTarget | null = null, view: TView | null = null) {
|
|
43
|
+
public constructor(options: TOptions, targetElement: TTarget | null = null, view: TView | null = null) {
|
|
45
44
|
this.options = options;
|
|
46
45
|
this.targetElement = targetElement;
|
|
47
46
|
this.view = view;
|
|
@@ -52,7 +51,7 @@ export class Model<
|
|
|
52
51
|
*
|
|
53
52
|
* @param {TTarget|null} targetElement - The new target element to bind to the model.
|
|
54
53
|
*/
|
|
55
|
-
update(targetElement: TTarget | null): void {
|
|
54
|
+
public update(targetElement: TTarget | null): void {
|
|
56
55
|
this.targetElement = targetElement;
|
|
57
56
|
this.onTargetChanged();
|
|
58
57
|
}
|
|
@@ -60,7 +59,7 @@ export class Model<
|
|
|
60
59
|
/**
|
|
61
60
|
* Cleans up references and invokes the removal hook when the model is no longer needed.
|
|
62
61
|
*/
|
|
63
|
-
remove() {
|
|
62
|
+
public remove() {
|
|
64
63
|
this.targetElement = null;
|
|
65
64
|
this.view?.getView()?.remove?.();
|
|
66
65
|
this.view = null;
|
|
@@ -72,11 +71,11 @@ export class Model<
|
|
|
72
71
|
* Hook invoked whenever the target element changes.
|
|
73
72
|
* Override in subclasses to react to attribute/content updates (e.g., text, disabled state).
|
|
74
73
|
*/
|
|
75
|
-
onTargetChanged(): void { }
|
|
74
|
+
public onTargetChanged(): void { }
|
|
76
75
|
|
|
77
76
|
/**
|
|
78
77
|
* Hook invoked whenever the target element is removed.
|
|
79
78
|
* Override in subclasses to react to removal of the element.
|
|
80
79
|
*/
|
|
81
|
-
onRemove(): void {}
|
|
80
|
+
public onRemove(): void {}
|
|
82
81
|
}
|
|
@@ -11,9 +11,9 @@ export class RecyclerView<
|
|
|
11
11
|
TItem extends ModelContract<any, any>,
|
|
12
12
|
TAdapter extends AdapterContract<TItem>
|
|
13
13
|
> implements RecyclerViewContract<TAdapter> {
|
|
14
|
-
viewElement: HTMLDivElement | null = null;
|
|
14
|
+
public viewElement: HTMLDivElement | null = null;
|
|
15
15
|
|
|
16
|
-
adapter: TAdapter | null = null;
|
|
16
|
+
public adapter: TAdapter | null = null;
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Constructs a RecyclerView with an optional container element that will host rendered item views.
|
|
@@ -29,7 +29,7 @@ export class RecyclerView<
|
|
|
29
29
|
*
|
|
30
30
|
* @param {HTMLDivElement} viewElement - The root element for rendering.
|
|
31
31
|
*/
|
|
32
|
-
setView(viewElement: HTMLDivElement): void {
|
|
32
|
+
public setView(viewElement: HTMLDivElement): void {
|
|
33
33
|
this.viewElement = viewElement;
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -41,7 +41,7 @@ export class RecyclerView<
|
|
|
41
41
|
*
|
|
42
42
|
* @param {TAdapter} adapter - The adapter managing models and their views.
|
|
43
43
|
*/
|
|
44
|
-
setAdapter(adapter: TAdapter): void {
|
|
44
|
+
public setAdapter(adapter: TAdapter): void {
|
|
45
45
|
this.adapter = adapter;
|
|
46
46
|
|
|
47
47
|
adapter.onPropChanging("items", () => {
|
|
@@ -59,7 +59,7 @@ export class RecyclerView<
|
|
|
59
59
|
* Removes all child nodes from the rendering container, if present.
|
|
60
60
|
* Used prior to re-rendering or when items are changing.
|
|
61
61
|
*/
|
|
62
|
-
clear(): void {
|
|
62
|
+
public clear(): void {
|
|
63
63
|
if (!this.viewElement) return;
|
|
64
64
|
this.viewElement.replaceChildren();
|
|
65
65
|
}
|
|
@@ -68,7 +68,7 @@ export class RecyclerView<
|
|
|
68
68
|
* Renders the current adapter contents into the container.
|
|
69
69
|
* No-ops if either the adapter or the container is not set.
|
|
70
70
|
*/
|
|
71
|
-
render(): void {
|
|
71
|
+
public render(): void {
|
|
72
72
|
if (!this.adapter || !this.viewElement) return;
|
|
73
73
|
this.adapter.updateRecyclerView(this.viewElement);
|
|
74
74
|
}
|
|
@@ -79,7 +79,7 @@ export class RecyclerView<
|
|
|
79
79
|
*
|
|
80
80
|
* @param isUpdate - Indicates if this refresh is due to an update operation.
|
|
81
81
|
*/
|
|
82
|
-
refresh(isUpdate: boolean): void {
|
|
82
|
+
public refresh(isUpdate: boolean): void {
|
|
83
83
|
this.render();
|
|
84
84
|
}
|
|
85
85
|
}
|
package/src/ts/core/base/view.ts
CHANGED
|
@@ -6,16 +6,16 @@ import type { ViewContract } from "../../types/core/base/view.type";
|
|
|
6
6
|
* @implements {ViewContract<TTags>}
|
|
7
7
|
*/
|
|
8
8
|
export class View<TTags extends Record<string, HTMLElement>> implements ViewContract<TTags> {
|
|
9
|
-
parent: HTMLElement | null = null;
|
|
9
|
+
public parent: HTMLElement | null = null;
|
|
10
10
|
|
|
11
|
-
view: MountViewResult<TTags> | null = null;
|
|
11
|
+
public view: MountViewResult<TTags> | null = null;
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Initializes the view with a parent container element that will host its rendered content.
|
|
15
15
|
*
|
|
16
16
|
* @param {HTMLElement} parent - The parent element into which this view will render.
|
|
17
17
|
*/
|
|
18
|
-
constructor(parent: HTMLElement) {
|
|
18
|
+
public constructor(parent: HTMLElement) {
|
|
19
19
|
this.parent = parent;
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -23,20 +23,20 @@ export class View<TTags extends Record<string, HTMLElement>> implements ViewCont
|
|
|
23
23
|
* Renders the view into the parent container.
|
|
24
24
|
* Override in subclasses to create DOM structure and mount tags.
|
|
25
25
|
*/
|
|
26
|
-
render(): void { }
|
|
26
|
+
public render(): void { }
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Updates the view to reflect model or state changes.
|
|
30
30
|
* Override in subclasses to patch DOM nodes without full re-render.
|
|
31
31
|
*/
|
|
32
|
-
update(): void { }
|
|
32
|
+
public update(): void { }
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Returns the root HTMLElement of the mounted view.
|
|
36
36
|
*
|
|
37
37
|
* @returns {HTMLElement} - The root view element.
|
|
38
38
|
*/
|
|
39
|
-
getView(): HTMLElement {
|
|
39
|
+
public getView(): HTMLElement {
|
|
40
40
|
if (!this.view?.view) throw new Error("View is not mounted. Did you forget to set this.view?");
|
|
41
41
|
return this.view.view;
|
|
42
42
|
}
|