selective-ui 1.0.2 → 1.0.3

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 (67) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +7 -2
  3. package/dist/selective-ui.css +567 -567
  4. package/dist/selective-ui.css.map +1 -1
  5. package/dist/selective-ui.esm.js +6046 -6046
  6. package/dist/selective-ui.esm.js.map +1 -1
  7. package/dist/selective-ui.esm.min.js +1 -1
  8. package/dist/selective-ui.esm.min.js.br +0 -0
  9. package/dist/selective-ui.min.js +1 -1
  10. package/dist/selective-ui.min.js.br +0 -0
  11. package/dist/selective-ui.umd.js +6046 -6046
  12. package/dist/selective-ui.umd.js.map +1 -1
  13. package/package.json +68 -68
  14. package/src/css/components/accessorybox.css +63 -63
  15. package/src/css/components/directive.css +19 -19
  16. package/src/css/components/empty-state.css +25 -25
  17. package/src/css/components/loading-state.css +25 -25
  18. package/src/css/components/optgroup.css +61 -61
  19. package/src/css/components/option-handle.css +33 -33
  20. package/src/css/components/option.css +129 -129
  21. package/src/css/components/placeholder.css +14 -14
  22. package/src/css/components/popup.css +38 -38
  23. package/src/css/components/searchbox.css +28 -28
  24. package/src/css/components/selectbox.css +53 -53
  25. package/src/css/index.css +74 -74
  26. package/src/js/adapter/mixed-adapter.js +434 -434
  27. package/src/js/components/accessorybox.js +124 -124
  28. package/src/js/components/directive.js +37 -37
  29. package/src/js/components/empty-state.js +67 -67
  30. package/src/js/components/loading-state.js +59 -59
  31. package/src/js/components/option-handle.js +113 -113
  32. package/src/js/components/placeholder.js +56 -56
  33. package/src/js/components/popup.js +470 -470
  34. package/src/js/components/searchbox.js +167 -167
  35. package/src/js/components/selectbox.js +692 -692
  36. package/src/js/core/base/adapter.js +162 -162
  37. package/src/js/core/base/model.js +59 -59
  38. package/src/js/core/base/recyclerview.js +82 -82
  39. package/src/js/core/base/view.js +62 -62
  40. package/src/js/core/model-manager.js +286 -286
  41. package/src/js/core/search-controller.js +521 -521
  42. package/src/js/index.js +136 -136
  43. package/src/js/models/group-model.js +142 -142
  44. package/src/js/models/option-model.js +236 -236
  45. package/src/js/services/dataset-observer.js +73 -73
  46. package/src/js/services/ea-observer.js +87 -87
  47. package/src/js/services/effector.js +403 -403
  48. package/src/js/services/refresher.js +39 -39
  49. package/src/js/services/resize-observer.js +151 -151
  50. package/src/js/services/select-observer.js +60 -60
  51. package/src/js/types/adapter.type.js +32 -32
  52. package/src/js/types/effector.type.js +23 -23
  53. package/src/js/types/ievents.type.js +10 -10
  54. package/src/js/types/libs.type.js +27 -27
  55. package/src/js/types/model.type.js +11 -11
  56. package/src/js/types/recyclerview.type.js +11 -11
  57. package/src/js/types/resize-observer.type.js +18 -18
  58. package/src/js/types/view.group.type.js +12 -12
  59. package/src/js/types/view.option.type.js +14 -14
  60. package/src/js/types/view.type.js +10 -10
  61. package/src/js/utils/guard.js +46 -46
  62. package/src/js/utils/ievents.js +83 -83
  63. package/src/js/utils/istorage.js +60 -60
  64. package/src/js/utils/libs.js +618 -618
  65. package/src/js/utils/selective.js +385 -385
  66. package/src/js/views/group-view.js +102 -102
  67. package/src/js/views/option-view.js +152 -152
@@ -1,163 +1,163 @@
1
- import { Libs } from "../../utils/libs";
2
- import { Model } from "./model";
3
-
4
- /**
5
- * @template {ModelContract<any, any>} TItem
6
- * @implements {AdapterContract<TItem>}
7
- */
8
- export class Adapter {
9
- /** @type {TItem[]} */
10
- items = [];
11
- adapterKey = Libs.randomString(12);
12
-
13
- isSkipEvent = false;
14
-
15
-
16
- /**
17
- * Initializes the adapter with an optional array of items and invokes onInit()
18
- * to perform any subclass-specific setup. Accepts a generic list of models.
19
- *
20
- * @param {TItem[]} [items=[]] - Initial items to be managed by the adapter.
21
- */
22
- constructor(items = []) {
23
- this.items = items;
24
- this.onInit();
25
- }
26
-
27
- /**
28
- * Lifecycle hook called once after construction. Override in subclasses to
29
- * perform setup tasks (e.g., event wiring, cache building).
30
- */
31
- onInit() {}
32
-
33
- /**
34
- * Binds an item model to its viewer at a given position. If the item has not
35
- * been initialized yet, renders the viewer; otherwise triggers an update.
36
- *
37
- * @param {any} item - The model instance to bind to the view.
38
- * @param {any} viewer - The view instance responsible for rendering the model.
39
- * @param {number} position - The index of the item within the adapter.
40
- */
41
- onViewHolder(item, viewer, position) {
42
- if (!item.isInit) {
43
- viewer.render();
44
- }
45
- else {
46
- viewer.update();
47
- }
48
- }
49
-
50
- /**
51
- * Registers a pre-change (debounced) callback for a property change pipeline.
52
- * The callback is scheduled with a minimal delay to batch rapid updates.
53
- *
54
- * @param {string} propName - The property name to observe (e.g., "items").
55
- * @param {Function} callback - Function to execute before the property changes.
56
- */
57
- onPropChanging(propName, callback) {
58
- Libs.timerProcess.setExecute(`${propName}ing_${this.adapterKey}`, callback, 1);
59
- }
60
-
61
- /**
62
- * Registers a post-change callback for a property change pipeline.
63
- * The callback is executed after the property is updated.
64
- *
65
- * @param {string} propName - The property name to observe (e.g., "items").
66
- * @param {Function} callback - Function to execute after the property changes.
67
- */
68
- onPropChanged(propName, callback) {
69
- Libs.timerProcess.setExecute(`${propName}_${this.adapterKey}`, callback);
70
- }
71
-
72
- /**
73
- * Triggers the post-change pipeline for a given property, passing optional parameters
74
- * to registered callbacks. Use this after mutating adapter state.
75
- *
76
- * @param {string} propName - The property name to emit (e.g., "items").
77
- * @param {...any} params - Parameters forwarded to the callbacks.
78
- */
79
- changeProp(propName, ...params) {
80
- Libs.timerProcess.run(`${propName}_${this.adapterKey}`, ...params);
81
- }
82
-
83
- /**
84
- * Triggers the pre-change pipeline for a given property, passing optional parameters
85
- * to registered callbacks. Use this before mutating adapter state.
86
- *
87
- * @param {string} propName - The property name to emit (e.g., "items").
88
- * @param {...any} params - Parameters forwarded to the callbacks.
89
- */
90
- changingProp(propName, ...params) {
91
- Libs.timerProcess.run(`${propName}ing_${this.adapterKey}`, ...params);
92
- }
93
-
94
-
95
- /**
96
- * Creates and returns a viewer instance for the given item within the specified parent container.
97
- * Override in subclasses to return a concrete view implementation tailored to TItem.
98
- *
99
- * @param {HTMLElement} parent - The container element that will host the viewer.
100
- * @param {TItem} item - The model instance for which the viewer is created.
101
- * @returns {any} - The created viewer instance; null by default.
102
- */
103
- viewHolder(parent, item) {
104
- return null;
105
- }
106
-
107
- /**
108
- * Returns the total number of items currently managed by the adapter.
109
- *
110
- * @returns {number} - The item count.
111
- */
112
- itemCount() {
113
- return this.items.length;
114
- }
115
-
116
- /**
117
- * Replaces the adapter's items with a new collection, emitting pre-change and post-change
118
- * notifications to observers. Does not render; call updateRecyclerView() to apply to the DOM.
119
- *
120
- * @param {TItem[]} items - The new list of items to set.
121
- */
122
- setItems(items) {
123
- this.changingProp("items", items);
124
- this.items = items;
125
- this.changeProp("items", items);
126
- }
127
-
128
- /**
129
- * Synchronizes adapter items from an external source by delegating to setItems().
130
- * Useful for keeping adapter state aligned with another data store.
131
- *
132
- * @param {TItem[]} items - The source list of items to synchronize.
133
- */
134
- syncFromSource(items) {
135
- this.setItems(items);
136
- }
137
-
138
- /**
139
- * Iterates through all items and ensures each has a viewer. For new items, calls viewHolder()
140
- * to create the viewer, then binds via onViewHolder() and marks the item as initialized.
141
- *
142
- * @param {HTMLElement|null} parent - The container element in which item viewers are rendered.
143
- */
144
- updateRecyclerView(parent) {
145
- for (let index = 0; index < this.itemCount(); index++) {
146
- let viewer = this.items[index].view;
147
- if (!this.items[index].isInit) {
148
- viewer = this.viewHolder(parent, this.items[index]);
149
- }
150
- this.onViewHolder(this.items[index], viewer, index);
151
-
152
- this.items[index].isInit = true;
153
- }
154
- }
155
-
156
- /**
157
- * Updates adapter data without performing any default actions.
158
- * Override in subclasses to implement custom data refresh logic.
159
- *
160
- * @param {TItem[]} items - The incoming data to apply to the adapter.
161
- */
162
- updateData(items) { }
1
+ import { Libs } from "../../utils/libs";
2
+ import { Model } from "./model";
3
+
4
+ /**
5
+ * @template {ModelContract<any, any>} TItem
6
+ * @implements {AdapterContract<TItem>}
7
+ */
8
+ export class Adapter {
9
+ /** @type {TItem[]} */
10
+ items = [];
11
+ adapterKey = Libs.randomString(12);
12
+
13
+ isSkipEvent = false;
14
+
15
+
16
+ /**
17
+ * Initializes the adapter with an optional array of items and invokes onInit()
18
+ * to perform any subclass-specific setup. Accepts a generic list of models.
19
+ *
20
+ * @param {TItem[]} [items=[]] - Initial items to be managed by the adapter.
21
+ */
22
+ constructor(items = []) {
23
+ this.items = items;
24
+ this.onInit();
25
+ }
26
+
27
+ /**
28
+ * Lifecycle hook called once after construction. Override in subclasses to
29
+ * perform setup tasks (e.g., event wiring, cache building).
30
+ */
31
+ onInit() {}
32
+
33
+ /**
34
+ * Binds an item model to its viewer at a given position. If the item has not
35
+ * been initialized yet, renders the viewer; otherwise triggers an update.
36
+ *
37
+ * @param {any} item - The model instance to bind to the view.
38
+ * @param {any} viewer - The view instance responsible for rendering the model.
39
+ * @param {number} position - The index of the item within the adapter.
40
+ */
41
+ onViewHolder(item, viewer, position) {
42
+ if (!item.isInit) {
43
+ viewer.render();
44
+ }
45
+ else {
46
+ viewer.update();
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Registers a pre-change (debounced) callback for a property change pipeline.
52
+ * The callback is scheduled with a minimal delay to batch rapid updates.
53
+ *
54
+ * @param {string} propName - The property name to observe (e.g., "items").
55
+ * @param {Function} callback - Function to execute before the property changes.
56
+ */
57
+ onPropChanging(propName, callback) {
58
+ Libs.timerProcess.setExecute(`${propName}ing_${this.adapterKey}`, callback, 1);
59
+ }
60
+
61
+ /**
62
+ * Registers a post-change callback for a property change pipeline.
63
+ * The callback is executed after the property is updated.
64
+ *
65
+ * @param {string} propName - The property name to observe (e.g., "items").
66
+ * @param {Function} callback - Function to execute after the property changes.
67
+ */
68
+ onPropChanged(propName, callback) {
69
+ Libs.timerProcess.setExecute(`${propName}_${this.adapterKey}`, callback);
70
+ }
71
+
72
+ /**
73
+ * Triggers the post-change pipeline for a given property, passing optional parameters
74
+ * to registered callbacks. Use this after mutating adapter state.
75
+ *
76
+ * @param {string} propName - The property name to emit (e.g., "items").
77
+ * @param {...any} params - Parameters forwarded to the callbacks.
78
+ */
79
+ changeProp(propName, ...params) {
80
+ Libs.timerProcess.run(`${propName}_${this.adapterKey}`, ...params);
81
+ }
82
+
83
+ /**
84
+ * Triggers the pre-change pipeline for a given property, passing optional parameters
85
+ * to registered callbacks. Use this before mutating adapter state.
86
+ *
87
+ * @param {string} propName - The property name to emit (e.g., "items").
88
+ * @param {...any} params - Parameters forwarded to the callbacks.
89
+ */
90
+ changingProp(propName, ...params) {
91
+ Libs.timerProcess.run(`${propName}ing_${this.adapterKey}`, ...params);
92
+ }
93
+
94
+
95
+ /**
96
+ * Creates and returns a viewer instance for the given item within the specified parent container.
97
+ * Override in subclasses to return a concrete view implementation tailored to TItem.
98
+ *
99
+ * @param {HTMLElement} parent - The container element that will host the viewer.
100
+ * @param {TItem} item - The model instance for which the viewer is created.
101
+ * @returns {any} - The created viewer instance; null by default.
102
+ */
103
+ viewHolder(parent, item) {
104
+ return null;
105
+ }
106
+
107
+ /**
108
+ * Returns the total number of items currently managed by the adapter.
109
+ *
110
+ * @returns {number} - The item count.
111
+ */
112
+ itemCount() {
113
+ return this.items.length;
114
+ }
115
+
116
+ /**
117
+ * Replaces the adapter's items with a new collection, emitting pre-change and post-change
118
+ * notifications to observers. Does not render; call updateRecyclerView() to apply to the DOM.
119
+ *
120
+ * @param {TItem[]} items - The new list of items to set.
121
+ */
122
+ setItems(items) {
123
+ this.changingProp("items", items);
124
+ this.items = items;
125
+ this.changeProp("items", items);
126
+ }
127
+
128
+ /**
129
+ * Synchronizes adapter items from an external source by delegating to setItems().
130
+ * Useful for keeping adapter state aligned with another data store.
131
+ *
132
+ * @param {TItem[]} items - The source list of items to synchronize.
133
+ */
134
+ syncFromSource(items) {
135
+ this.setItems(items);
136
+ }
137
+
138
+ /**
139
+ * Iterates through all items and ensures each has a viewer. For new items, calls viewHolder()
140
+ * to create the viewer, then binds via onViewHolder() and marks the item as initialized.
141
+ *
142
+ * @param {HTMLElement|null} parent - The container element in which item viewers are rendered.
143
+ */
144
+ updateRecyclerView(parent) {
145
+ for (let index = 0; index < this.itemCount(); index++) {
146
+ let viewer = this.items[index].view;
147
+ if (!this.items[index].isInit) {
148
+ viewer = this.viewHolder(parent, this.items[index]);
149
+ }
150
+ this.onViewHolder(this.items[index], viewer, index);
151
+
152
+ this.items[index].isInit = true;
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Updates adapter data without performing any default actions.
158
+ * Override in subclasses to implement custom data refresh logic.
159
+ *
160
+ * @param {TItem[]} items - The incoming data to apply to the adapter.
161
+ */
162
+ updateData(items) { }
163
163
  }
@@ -1,59 +1,59 @@
1
- /**
2
- * @template TTarget
3
- * @template {Record<string, Element>} TTags
4
- * @template {ViewContract<TTags>} TView
5
- * @implements {ModelContract<TTarget, TView>}
6
- */
7
- export class Model {
8
- /** @type {TTarget | null} */
9
- targetElement = null;
10
-
11
- options = null;
12
-
13
- /** @type {TView | null} */
14
- view = null;
15
-
16
- position = -1;
17
-
18
- isInit = false;
19
-
20
- /**
21
- * Returns the current value from the underlying target element's "value" attribute.
22
- * For single-select, this is typically a string; for multi-select, may be an array depending on usage.
23
- *
24
- * @type {String|String[]}
25
- */
26
- get value() {
27
- return /** @type {HTMLElement} */ (this.targetElement).getAttribute("value");
28
- }
29
-
30
- /**
31
- * Constructs a Model instance with configuration options and optional bindings to a target element and view.
32
- * Stores references for later updates and rendering.
33
- *
34
- * @param {object} options - Configuration options for the model.
35
- * @param {TTarget|null} [targetElement=null] - The underlying element (e.g., <option> or group node).
36
- * @param {TView|null} [view=null] - The associated view responsible for rendering the model.
37
- */
38
- constructor(options, targetElement = null, view = null) {
39
- this.options = options;
40
- this.targetElement = targetElement;
41
- this.view = view;
42
- }
43
-
44
- /**
45
- * Updates the bound target element reference and invokes the change hook.
46
- *
47
- * @param {TTarget|null} targetElement - The new target element to bind to the model.
48
- */
49
- update(targetElement) {
50
- this.targetElement = targetElement;
51
- this.onTargetChanged();
52
- }
53
-
54
- /**
55
- * Hook invoked whenever the target element changes.
56
- * Override in subclasses to react to attribute/content updates (e.g., text, disabled state).
57
- */
58
- onTargetChanged() { }
59
- }
1
+ /**
2
+ * @template TTarget
3
+ * @template {Record<string, Element>} TTags
4
+ * @template {ViewContract<TTags>} TView
5
+ * @implements {ModelContract<TTarget, TView>}
6
+ */
7
+ export class Model {
8
+ /** @type {TTarget | null} */
9
+ targetElement = null;
10
+
11
+ options = null;
12
+
13
+ /** @type {TView | null} */
14
+ view = null;
15
+
16
+ position = -1;
17
+
18
+ isInit = false;
19
+
20
+ /**
21
+ * Returns the current value from the underlying target element's "value" attribute.
22
+ * For single-select, this is typically a string; for multi-select, may be an array depending on usage.
23
+ *
24
+ * @type {String|String[]}
25
+ */
26
+ get value() {
27
+ return /** @type {HTMLElement} */ (this.targetElement).getAttribute("value");
28
+ }
29
+
30
+ /**
31
+ * Constructs a Model instance with configuration options and optional bindings to a target element and view.
32
+ * Stores references for later updates and rendering.
33
+ *
34
+ * @param {object} options - Configuration options for the model.
35
+ * @param {TTarget|null} [targetElement=null] - The underlying element (e.g., <option> or group node).
36
+ * @param {TView|null} [view=null] - The associated view responsible for rendering the model.
37
+ */
38
+ constructor(options, targetElement = null, view = null) {
39
+ this.options = options;
40
+ this.targetElement = targetElement;
41
+ this.view = view;
42
+ }
43
+
44
+ /**
45
+ * Updates the bound target element reference and invokes the change hook.
46
+ *
47
+ * @param {TTarget|null} targetElement - The new target element to bind to the model.
48
+ */
49
+ update(targetElement) {
50
+ this.targetElement = targetElement;
51
+ this.onTargetChanged();
52
+ }
53
+
54
+ /**
55
+ * Hook invoked whenever the target element changes.
56
+ * Override in subclasses to react to attribute/content updates (e.g., text, disabled state).
57
+ */
58
+ onTargetChanged() { }
59
+ }
@@ -1,83 +1,83 @@
1
- /**
2
- * @template {ModelContract<any, any>} TItem
3
- * @template {AdapterContract<TItem>} TAdapter
4
- * @implements {RecyclerViewContract<TAdapter>}
5
- */
6
- export class RecyclerView {
7
- /**
8
- * @type {HTMLDivElement}
9
- */
10
- viewElement = null;
11
-
12
- /**
13
- * @type {TAdapter}
14
- */
15
- adapter = null;
16
-
17
- /**
18
- * Constructs a RecyclerView with an optional container element that will host rendered item views.
19
- *
20
- * @param {HTMLDivElement|null} [viewElement=null] - The root element where the adapter will render items.
21
- */
22
- constructor(viewElement = null) {
23
- this.viewElement = viewElement;
24
- }
25
-
26
- /**
27
- * Sets or updates the container element used to render the adapter's item views.
28
- *
29
- * @param {HTMLDivElement} viewElement - The root element for rendering.
30
- */
31
- setView(viewElement) {
32
- this.viewElement = viewElement;
33
- }
34
-
35
- /**
36
- * Attaches an adapter to the RecyclerView and wires item-change lifecycle:
37
- * - onPropChanging("items"): clears the container before items change,
38
- * - onPropChanged("items"): re-renders after items change,
39
- * then performs an initial render.
40
- *
41
- * @param {TAdapter} adapter - The adapter managing models and their views.
42
- */
43
- setAdapter(adapter) {
44
- this.adapter = adapter;
45
-
46
- adapter.onPropChanging("items", () => {
47
- this.clear();
48
- });
49
-
50
- adapter.onPropChanged("items", () => {
51
- this.render();
52
- });
53
-
54
- this.render();
55
- }
56
-
57
- /**
58
- * Removes all child nodes from the rendering container, if present.
59
- * Used prior to re-rendering or when items are changing.
60
- */
61
- clear() {
62
- if (!this.viewElement) return;
63
- this.viewElement.replaceChildren();
64
- }
65
-
66
- /**
67
- * Renders the current adapter contents into the container.
68
- * No-ops if either the adapter or the container is not set.
69
- */
70
- render() {
71
- if (!this.adapter || !this.viewElement) return;
72
-
73
- this.adapter.updateRecyclerView(this.viewElement);
74
- }
75
-
76
- /**
77
- * Forces a re-render of the current adapter state into the container.
78
- * Useful when visual updates are required without changing the data.
79
- */
80
- refresh() {
81
- this.render();
82
- }
1
+ /**
2
+ * @template {ModelContract<any, any>} TItem
3
+ * @template {AdapterContract<TItem>} TAdapter
4
+ * @implements {RecyclerViewContract<TAdapter>}
5
+ */
6
+ export class RecyclerView {
7
+ /**
8
+ * @type {HTMLDivElement}
9
+ */
10
+ viewElement = null;
11
+
12
+ /**
13
+ * @type {TAdapter}
14
+ */
15
+ adapter = null;
16
+
17
+ /**
18
+ * Constructs a RecyclerView with an optional container element that will host rendered item views.
19
+ *
20
+ * @param {HTMLDivElement|null} [viewElement=null] - The root element where the adapter will render items.
21
+ */
22
+ constructor(viewElement = null) {
23
+ this.viewElement = viewElement;
24
+ }
25
+
26
+ /**
27
+ * Sets or updates the container element used to render the adapter's item views.
28
+ *
29
+ * @param {HTMLDivElement} viewElement - The root element for rendering.
30
+ */
31
+ setView(viewElement) {
32
+ this.viewElement = viewElement;
33
+ }
34
+
35
+ /**
36
+ * Attaches an adapter to the RecyclerView and wires item-change lifecycle:
37
+ * - onPropChanging("items"): clears the container before items change,
38
+ * - onPropChanged("items"): re-renders after items change,
39
+ * then performs an initial render.
40
+ *
41
+ * @param {TAdapter} adapter - The adapter managing models and their views.
42
+ */
43
+ setAdapter(adapter) {
44
+ this.adapter = adapter;
45
+
46
+ adapter.onPropChanging("items", () => {
47
+ this.clear();
48
+ });
49
+
50
+ adapter.onPropChanged("items", () => {
51
+ this.render();
52
+ });
53
+
54
+ this.render();
55
+ }
56
+
57
+ /**
58
+ * Removes all child nodes from the rendering container, if present.
59
+ * Used prior to re-rendering or when items are changing.
60
+ */
61
+ clear() {
62
+ if (!this.viewElement) return;
63
+ this.viewElement.replaceChildren();
64
+ }
65
+
66
+ /**
67
+ * Renders the current adapter contents into the container.
68
+ * No-ops if either the adapter or the container is not set.
69
+ */
70
+ render() {
71
+ if (!this.adapter || !this.viewElement) return;
72
+
73
+ this.adapter.updateRecyclerView(this.viewElement);
74
+ }
75
+
76
+ /**
77
+ * Forces a re-render of the current adapter state into the container.
78
+ * Useful when visual updates are required without changing the data.
79
+ */
80
+ refresh() {
81
+ this.render();
82
+ }
83
83
  }