selective-ui 1.0.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.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2 -0
  3. package/dist/selective-ui.css +569 -0
  4. package/dist/selective-ui.css.map +1 -0
  5. package/dist/selective-ui.esm.js +6101 -0
  6. package/dist/selective-ui.esm.js.map +1 -0
  7. package/dist/selective-ui.esm.min.js +1 -0
  8. package/dist/selective-ui.esm.min.js.br +0 -0
  9. package/dist/selective-ui.min.css +1 -0
  10. package/dist/selective-ui.min.css.br +0 -0
  11. package/dist/selective-ui.min.js +2 -0
  12. package/dist/selective-ui.min.js.br +0 -0
  13. package/dist/selective-ui.umd.js +6115 -0
  14. package/dist/selective-ui.umd.js.map +1 -0
  15. package/package.json +68 -0
  16. package/src/css/components/accessorybox.css +64 -0
  17. package/src/css/components/directive.css +20 -0
  18. package/src/css/components/empty-state.css +26 -0
  19. package/src/css/components/loading-state.css +26 -0
  20. package/src/css/components/optgroup.css +62 -0
  21. package/src/css/components/option-handle.css +34 -0
  22. package/src/css/components/option.css +130 -0
  23. package/src/css/components/placeholder.css +15 -0
  24. package/src/css/components/popup.css +39 -0
  25. package/src/css/components/searchbox.css +29 -0
  26. package/src/css/components/selectbox.css +54 -0
  27. package/src/css/index.css +75 -0
  28. package/src/js/adapter/mixed-adapter.js +435 -0
  29. package/src/js/components/accessorybox.js +125 -0
  30. package/src/js/components/directive.js +38 -0
  31. package/src/js/components/empty-state.js +68 -0
  32. package/src/js/components/loading-state.js +60 -0
  33. package/src/js/components/option-handle.js +114 -0
  34. package/src/js/components/placeholder.js +57 -0
  35. package/src/js/components/popup.js +471 -0
  36. package/src/js/components/searchbox.js +168 -0
  37. package/src/js/components/selectbox.js +693 -0
  38. package/src/js/core/base/adapter.js +163 -0
  39. package/src/js/core/base/model.js +59 -0
  40. package/src/js/core/base/recyclerview.js +83 -0
  41. package/src/js/core/base/view.js +62 -0
  42. package/src/js/core/model-manager.js +286 -0
  43. package/src/js/core/search-controller.js +522 -0
  44. package/src/js/index.js +137 -0
  45. package/src/js/models/group-model.js +143 -0
  46. package/src/js/models/option-model.js +237 -0
  47. package/src/js/services/dataset-observer.js +73 -0
  48. package/src/js/services/ea-observer.js +88 -0
  49. package/src/js/services/effector.js +404 -0
  50. package/src/js/services/refresher.js +40 -0
  51. package/src/js/services/resize-observer.js +152 -0
  52. package/src/js/services/select-observer.js +61 -0
  53. package/src/js/types/adapter.type.js +33 -0
  54. package/src/js/types/effector.type.js +24 -0
  55. package/src/js/types/ievents.type.js +11 -0
  56. package/src/js/types/libs.type.js +28 -0
  57. package/src/js/types/model.type.js +11 -0
  58. package/src/js/types/recyclerview.type.js +12 -0
  59. package/src/js/types/resize-observer.type.js +19 -0
  60. package/src/js/types/view.group.type.js +13 -0
  61. package/src/js/types/view.option.type.js +15 -0
  62. package/src/js/types/view.type.js +11 -0
  63. package/src/js/utils/guard.js +47 -0
  64. package/src/js/utils/ievents.js +83 -0
  65. package/src/js/utils/istorage.js +61 -0
  66. package/src/js/utils/libs.js +619 -0
  67. package/src/js/utils/selective.js +386 -0
  68. package/src/js/views/group-view.js +103 -0
  69. package/src/js/views/option-view.js +153 -0
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @typedef {Object} SizeObject
3
+ * @property {number} width
4
+ * @property {number} height
5
+ */
6
+
7
+ /**
8
+ * @typedef {Object} DimensionObject
9
+ * @property {number} width
10
+ * @property {number} height
11
+ * @property {number} scrollHeight
12
+ */
13
+
14
+ /**
15
+ * @typedef {Object} EffectorInterface
16
+ * @property {(query: string | HTMLElement) => void} setElement
17
+ * @property {HTMLElement} element
18
+ * @property {(object: {}) => EffectorInterface} expand
19
+ * @property {() => EffectorInterface} cancel
20
+ * @property {(object: {}) => EffectorInterface} collapse
21
+ * @property {(object: {}) => EffectorInterface} resize
22
+ * @property {boolean} isAnimating
23
+ * @property {(string: "flex") => DimensionObject} getHiddenDimensions
24
+ */
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @typedef {Object} IEventCallback
3
+ * @property {() => void} stopPropagation
4
+ * @property {() => void} cancel
5
+ */
6
+
7
+ /**
8
+ * @typedef {Object} IEventToken
9
+ * @property {boolean} isContinue
10
+ * @property {boolean} isCancel
11
+ */
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @template TTags
3
+ * @typedef {{
4
+ * id: string
5
+ * view: HTMLElement
6
+ * tags: TTags
7
+ * }} MountViewResult
8
+ */
9
+
10
+ /**
11
+ * @typedef {Object} NodeSpec
12
+ * @property {string} [node]
13
+ * @property {string|string[]} [classList]
14
+ * @property {Object} [style]
15
+ * @property {Object} [dataset]
16
+ * @property {string} [innerHTML]
17
+ * @property {string} [textContent]
18
+ * @property {string} [role]
19
+ * @property {string} [ariaLive]
20
+ * @property {string} [ariaLabel]
21
+ * @property {string} [ariaLabelledby]
22
+ * @property {string} [ariaControls]
23
+ * @property {string} [ariaHaspopup]
24
+ * @property {string} [ariaMultiselectable]
25
+ * @property {string} [ariaAutocomplete]
26
+ * @property {string} [tabIndex]
27
+ * @property {Record<string, EventListenerOrEventListenerObject>} [event]
28
+ */
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @template TTarget
3
+ * @template {ViewContract<any>} TView
4
+ * @typedef {Object} ModelContract
5
+ *
6
+ * @property {TTarget | null} targetElement
7
+ * @property {TView | null} view
8
+ * @property {any} value
9
+ * @property {number} position
10
+ * @property {boolean} isInit
11
+ */
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @template TAdapter extends AdapterContract
3
+ * @typedef {Object} RecyclerViewContract
4
+ *
5
+ * @property {HTMLElement | null} viewElement - The container element for the recycler view
6
+ * @property {TAdapter | null} adapter - The adapter instance controlling the items
7
+ * @property {(viewElement: HTMLElement) => void} setView - Set or change the container element
8
+ * @property {(adapter: TAdapter) => void} setAdapter - Attach an adapter and refresh the view
9
+ * @property {() => void} render - Render all item views inside the container
10
+ * @property {() => void} clear - Clear all item views from the container
11
+ * @property {() => void} refresh - Refresh item views from the container
12
+ */
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @typedef {Object} BoxEdges
3
+ * @property {number} top
4
+ * @property {number} right
5
+ * @property {number} bottom
6
+ * @property {number} left
7
+ */
8
+
9
+ /**
10
+ * @typedef {Object} ElementMetrics
11
+ * @property {number} width
12
+ * @property {number} height
13
+ * @property {number} top
14
+ * @property {number} left
15
+ *
16
+ * @property {BoxEdges} padding
17
+ * @property {BoxEdges} border
18
+ * @property {BoxEdges} margin
19
+ */
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @typedef {{
3
+ * GroupView: HTMLDivElement
4
+ * GroupHeader: HTMLDivElement
5
+ * GroupItems: HTMLDivElement
6
+ * }} GroupViewTags
7
+ */
8
+
9
+ /**
10
+ * @typedef {MountViewResult<GroupViewTags> & {
11
+ * view: Element
12
+ * }} GroupViewResult
13
+ */
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @typedef {{
3
+ * OptionView: HTMLDivElement,
4
+ * OptionInput: HTMLInputElement,
5
+ * OptionLabel: HTMLLabelElement,
6
+ * LabelContent: HTMLDivElement
7
+ * OptionImage: HTMLImageElement
8
+ * }} OptionViewTags
9
+ */
10
+
11
+ /**
12
+ * @typedef {MountViewResult<OptionViewTags> & {
13
+ * view: Element
14
+ * }} OptionViewResult
15
+ */
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @template {Record<string, Element>} TTags
3
+ * @typedef {Object} ViewContract
4
+ *
5
+ * @property {Element | null} parent
6
+ * @property {MountViewResult<TTags> | null} view
7
+ * @property {() => void} render
8
+ * @property {<K extends keyof TTags>(tag: K) => TTags[K]} getTag
9
+ * @property {() => TTags} getTags
10
+ * @property {() => Element} getView
11
+ */
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Checks for a previously loaded global library instance by name.
3
+ * If found (with `__loaded` flag), logs a warning and returns true; otherwise
4
+ * initializes a loading placeholder on `window[name]` and returns false.
5
+ *
6
+ * @param {string} LIB_NAME - The global namespace key to check on `window`.
7
+ * @returns {boolean} - True if a loaded instance already exists; false otherwise.
8
+ */
9
+ export function checkDuplicate(LIB_NAME) {
10
+ if (typeof window === "undefined") return false;
11
+
12
+ if (window[LIB_NAME] && window[LIB_NAME].__loaded) {
13
+ console.warn(
14
+ `[${LIB_NAME}] Already loaded (v${window[LIB_NAME].__version}). ` +
15
+ `Using existing instance. Please remove duplicate <script> tags.`
16
+ );
17
+ return true;
18
+ }
19
+
20
+ window[LIB_NAME] = window[LIB_NAME] || {};
21
+ window[LIB_NAME].__loading = true;
22
+ return false;
23
+ }
24
+
25
+ /**
26
+ * Marks a global library namespace as fully loaded, sets version metadata,
27
+ * merges its public API into `window[name]`, freezes the object to prevent
28
+ * further mutation, and logs a success message.
29
+ *
30
+ * @param {string} name - The global namespace key on `window`.
31
+ * @param {string} version - Semantic version string of the library.
32
+ * @param {Object} api - Public API surface to expose under `window[name]`.
33
+ * @returns {void}
34
+ */
35
+ export function markLoaded(name, version, api) {
36
+ if (typeof window === "undefined") return;
37
+
38
+ window[name].__loaded = true;
39
+ window[name].__loading = false;
40
+ window[name].__version = version;
41
+
42
+ Object.assign(window[name], api);
43
+
44
+ Object.freeze(window[name]);
45
+
46
+ console.log(`[${name}] v${version} loaded successfully`);
47
+ }
@@ -0,0 +1,83 @@
1
+
2
+ /**
3
+ * Provides a lightweight event utility with cancel/continue control:
4
+ * - buildEventToken(): creates a token/callback pair to control flow (stopPropagation/cancel).
5
+ * - callEvent(): invokes handlers in order, passing params; stops when canceled or propagation stopped.
6
+ * - trigger(): dispatches a native DOM Event on the given element.
7
+ * - callFunctions(): executes an array of functions with optional parameters.
8
+ */
9
+ export class iEvents {
10
+ /**
11
+ * Creates an event token and its controller callbacks.
12
+ * @returns {{ token: IEventToken, callback: IEventCallback }}
13
+ */
14
+ static buildEventToken() {
15
+ const privToken = { isContinue: true, isCancel: false };
16
+
17
+ const token = {
18
+ get isContinue() { return privToken.isContinue; },
19
+ get isCancel() { return privToken.isCancel; }
20
+ };
21
+
22
+ const callback = {
23
+ stopPropagation() { privToken.isContinue = false; },
24
+ cancel() { privToken.isCancel = true; privToken.isContinue = false; }
25
+ };
26
+
27
+ return { token, callback };
28
+ }
29
+
30
+ /**
31
+ * Calls event handlers sequentially with optional parameters and a control callback.
32
+ * Stops invoking further handlers if canceled or propagation is stopped.
33
+ *
34
+ * @template T
35
+ * @param {T[]|null} params
36
+ * @param {...Function} handles
37
+ * @returns {IEventToken}
38
+ */
39
+ static callEvent(params, ...handles) {
40
+ const { token, callback } = this.buildEventToken();
41
+
42
+ for (let i = 0; i < handles.length; i++) {
43
+ const handle = handles[i];
44
+
45
+ if (typeof handle !== 'function') continue;
46
+
47
+ if (params && Array.isArray(params)) {
48
+ handle(callback, ...params);
49
+ } else {
50
+ handle(callback);
51
+ }
52
+
53
+ if (token.isCancel || !token.isContinue) break;
54
+ }
55
+
56
+ return token;
57
+ }
58
+
59
+ /**
60
+ * Dispatches a native DOM event on the specified element.
61
+ * @param {HTMLElement|Window|Document} element
62
+ * @param {string} eventSTR
63
+ * @param {{bubbles?: boolean, cancelable?: boolean}} [opts]
64
+ */
65
+ static trigger(element, eventSTR, opts = { bubbles: true, cancelable: true }) {
66
+ const evt = new Event(eventSTR, opts);
67
+ element.dispatchEvent(evt);
68
+ return evt;
69
+ }
70
+
71
+ /**
72
+ * Invokes an array of functions with optional parameters.
73
+ * @param {Function[]} funcs
74
+ * @param {...any} params
75
+ */
76
+ static callFunctions(funcs, ...params) {
77
+ if (!Array.isArray(funcs)) return;
78
+ for (const fn of funcs) {
79
+ if (typeof fn !== 'function') continue;
80
+ fn(...params);
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @class
3
+ */
4
+ export class iStorage {
5
+ defaultConfig = {
6
+ showPanel: true,
7
+ accessoryStyle: "top",
8
+ multiple: false,
9
+ minWidth: "50px",
10
+ width: "0px",
11
+ offsetWidth: null,
12
+ minHeight: "30px",
13
+ height: "30px",
14
+ panelHeight: "220px",
15
+ panelMinHeight: "100px",
16
+ disabled: false,
17
+ readonly: false,
18
+ selectall: true,
19
+ keepSelected: true,
20
+ placeholder: "Chọn giá trị",
21
+ altMask: "",
22
+ autoclose: false,
23
+ autoscroll: true,
24
+ autofocus: true,
25
+ searchable: true,
26
+ loadingfield: true,
27
+ visible: true,
28
+ skipError: false,
29
+ customDelimiter: ",",
30
+ textLoading: "Đang xử lý...",
31
+ textNoData: "Không có dữ liệu",
32
+ textNotFound: "Không tìm thấy",
33
+ textSelectAll: "Chọn tất cả",
34
+ textDeselectAll: "Bỏ chọn",
35
+ textAccessoryDeselect: "Bỏ chọn: ",
36
+ animationtime: 200, // milisecond
37
+ delaysearchtime: 200, // milisecond
38
+ allowHtml: true,
39
+ maxSelected: 0,
40
+ labelHalign: "left",
41
+ labelValign: "center",
42
+ imageMode: false,
43
+ imageWidth: "60px",
44
+ imageHeight: "60px",
45
+ imageBorderRadius: "4px",
46
+ imagePosition: "right",
47
+ ajax: null,
48
+ on: {
49
+ load: [],
50
+ beforeShow: [],
51
+ show: [],
52
+ beforeChange: [],
53
+ change: [],
54
+ beforeClose: [],
55
+ close: []
56
+ }
57
+ };
58
+ bindedMap = new Map;
59
+ unbindedMap = new Map;
60
+ bindedCommand = [];
61
+ }