vueform-plugin-checkbox-select-all 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.
- package/dist/index.js +1 -0
- package/package.json +13 -6
- package/readme.md +3 -2
- package/src/index.js +0 -144
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{watch as v,onMounted as _,nextTick as g}from"vue";function p(){return{apply:["CheckboxElement","CheckboxgroupElement"],props:{controls:{type:Array,default:null},controller:{type:String,default:null}},setup(c,x,n){let{form$:i,el$:l}=n,o=e=>e?e.type==="checkbox"?e.value===!0:e.type==="checkboxgroup"?e.value?.length>0&&e.value?.length===e.items?.length:!1:!1,h=(e,t)=>{e&&(e.type==="checkbox"?(t&&e.value!==!0&&e.check(),!t&&e.value!==!1&&e.uncheck()):e.type==="checkboxgroup"&&(t&&!o(e)?e.checkAll():!t&&e.value?.length>0&&e.uncheckAll()))};return _(()=>{g(()=>{if(c.controls&&c.controls.length>0&&v(n.value,()=>{if(l.value.__locked){l.value.__locked=!1;return}let e=o(l.value);c.controls.forEach(t=>{let u=i.value.el$(t);u&&h(u,e)})}),c.controller&&v(n.value,()=>{if(l.value.__locked){l.value.__locked=!1;return}let e=i.value.el$(c.controller);if(!e||!e.controls)return;let t=e.controls.every(r=>{let a=i.value.el$(r);return a?o(a):!1}),u=o(e);t!==u&&(e.__locked=!0,h(e,t))}),l.value.type==="checkboxgroup"){let e=l.value.items.find(t=>t.groupController);if(e){let t=e.value,u=l.value.items.filter(r=>r.value!==t).map(r=>r.value);v(n.value,(r,a)=>{if(l.value.__lockedInternal){l.value.__lockedInternal=!1;return}let k=a.includes(t),s=r.includes(t);if(!k&&s){l.value.__lockedInternal=!0,l.value.checkAll();return}if(k&&!s){l.value.__lockedInternal=!0,l.value.uncheckAll();return}let d=u.every(f=>r.includes(f));s&&!d?(l.value.__lockedInternal=!0,l.value.value=r.filter(f=>f!==t)):!s&&d&&(l.value.__lockedInternal=!0,l.value.value=[...r,t])})}}})}),n}}}export{p as default};
|
package/package.json
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vueform-plugin-checkbox-select-all",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Bi-directional Select All logic for Vueform's Checkbox and Checkboxgroup elements",
|
|
5
|
-
"main": "
|
|
5
|
+
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "esbuild src/index.js --bundle --minify --format=esm --outfile=dist/index.js --external:vue --external:@vueform/vueform",
|
|
9
|
+
"prepublishOnly": "npm run build"
|
|
10
|
+
},
|
|
7
11
|
"files": [
|
|
8
|
-
"
|
|
12
|
+
"dist"
|
|
9
13
|
],
|
|
10
14
|
"peerDependencies": {
|
|
11
|
-
"
|
|
12
|
-
"
|
|
15
|
+
"@vueform/vueform": "^1.0.0",
|
|
16
|
+
"vue": "^3.0.0"
|
|
13
17
|
},
|
|
14
18
|
"keywords": [
|
|
15
19
|
"vueform",
|
|
@@ -18,5 +22,8 @@
|
|
|
18
22
|
"select-all"
|
|
19
23
|
],
|
|
20
24
|
"author": "Mohieb Al-Hesan",
|
|
21
|
-
"license": "MIT"
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"esbuild": "^0.27.2"
|
|
28
|
+
}
|
|
22
29
|
}
|
package/readme.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# Vueform Select All Checkboxes Plugin
|
|
2
2
|
|
|
3
|
-
This plugin enables complex "Select All" logic for Vueform. It handles bi-directional synchronization (Parent
|
|
3
|
+
This plugin enables complex "Select All" logic for Vueform. It handles bi-directional synchronization (Parent <--> Child) and prevents infinite loops using an internal locking mechanism. It supports standard checkboxes, checkbox groups, and nested structures.
|
|
4
4
|
|
|
5
5
|
## 📦 Installation
|
|
6
6
|
|
|
7
7
|
### 1. Install via NPM
|
|
8
|
+
|
|
8
9
|
Run the following command in your project root:
|
|
9
10
|
|
|
10
11
|
```bash
|
|
@@ -238,4 +239,4 @@ A group that contains its own "All" option inside the list, and a main checkbox
|
|
|
238
239
|
text: "Save My Selections",
|
|
239
240
|
},
|
|
240
241
|
}
|
|
241
|
-
```
|
|
242
|
+
```
|
package/src/index.js
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { watch, onMounted, nextTick } from "vue";
|
|
2
|
-
|
|
3
|
-
export default function CheckboxSelectAll() {
|
|
4
|
-
return {
|
|
5
|
-
apply: ["CheckboxElement", "CheckboxgroupElement"],
|
|
6
|
-
props: {
|
|
7
|
-
controls: { type: Array, default: null }, // External: Downstream
|
|
8
|
-
controller: { type: String, default: null }, // External: Upstream
|
|
9
|
-
},
|
|
10
|
-
setup(props, context, component) {
|
|
11
|
-
const { form$, el$ } = component;
|
|
12
|
-
|
|
13
|
-
// --- Helpers ---
|
|
14
|
-
const isComplete = (el) => {
|
|
15
|
-
if (!el) return false;
|
|
16
|
-
if (el.type === "checkbox") return el.value === true;
|
|
17
|
-
if (el.type === "checkboxgroup") {
|
|
18
|
-
// Complete if selected count equals total options count
|
|
19
|
-
return el.value?.length > 0 && el.value?.length === el.items?.length;
|
|
20
|
-
}
|
|
21
|
-
return false;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const setElementState = (el, makeChecked) => {
|
|
25
|
-
if (!el) return;
|
|
26
|
-
if (el.type === "checkbox") {
|
|
27
|
-
if (makeChecked && el.value !== true) el.check();
|
|
28
|
-
if (!makeChecked && el.value !== false) el.uncheck();
|
|
29
|
-
} else if (el.type === "checkboxgroup") {
|
|
30
|
-
if (makeChecked && !isComplete(el)) el.checkAll();
|
|
31
|
-
else if (!makeChecked && el.value?.length > 0) el.uncheckAll();
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
onMounted(() => {
|
|
36
|
-
nextTick(() => {
|
|
37
|
-
// ---------------------------------------------------------
|
|
38
|
-
// 1. EXTERNAL DOWNSTREAM (Main Controller -> This Element)
|
|
39
|
-
// ---------------------------------------------------------
|
|
40
|
-
if (props.controls && props.controls.length > 0) {
|
|
41
|
-
watch(component.value, () => {
|
|
42
|
-
if (el$.value.__locked) {
|
|
43
|
-
el$.value.__locked = false;
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
const shouldCheck = isComplete(el$.value);
|
|
47
|
-
props.controls.forEach((path) => {
|
|
48
|
-
const child = form$.value.el$(path);
|
|
49
|
-
if (child) setElementState(child, shouldCheck);
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// ---------------------------------------------------------
|
|
55
|
-
// 2. EXTERNAL UPSTREAM (This Element -> Main Controller)
|
|
56
|
-
// ---------------------------------------------------------
|
|
57
|
-
if (props.controller) {
|
|
58
|
-
watch(component.value, () => {
|
|
59
|
-
if (el$.value.__locked) {
|
|
60
|
-
el$.value.__locked = false;
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
const parent = form$.value.el$(props.controller);
|
|
64
|
-
if (!parent || !parent.controls) return;
|
|
65
|
-
|
|
66
|
-
const allSiblingsChecked = parent.controls.every((path) => {
|
|
67
|
-
const sibling = form$.value.el$(path);
|
|
68
|
-
return sibling ? isComplete(sibling) : false;
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
const parentIsChecked = isComplete(parent);
|
|
72
|
-
if (allSiblingsChecked !== parentIsChecked) {
|
|
73
|
-
parent.__locked = true;
|
|
74
|
-
setElementState(parent, allSiblingsChecked);
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// ---------------------------------------------------------
|
|
80
|
-
// 3. INTERNAL GROUP LOGIC (CheckboxGroup Only)
|
|
81
|
-
// Handles the "All" option inside the items array
|
|
82
|
-
// ---------------------------------------------------------
|
|
83
|
-
if (el$.value.type === "checkboxgroup") {
|
|
84
|
-
// Find the "All" option based on the custom property 'groupController'
|
|
85
|
-
const controllerItem = el$.value.items.find(
|
|
86
|
-
(option) => option.groupController
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
if (controllerItem) {
|
|
90
|
-
const ctrlVal = controllerItem.value;
|
|
91
|
-
const otherVals = el$.value.items
|
|
92
|
-
.filter((i) => i.value !== ctrlVal)
|
|
93
|
-
.map((i) => i.value);
|
|
94
|
-
|
|
95
|
-
watch(component.value, (newVal, oldVal) => {
|
|
96
|
-
// If locked by external logic, skip internal calculation
|
|
97
|
-
if (el$.value.__lockedInternal) {
|
|
98
|
-
el$.value.__lockedInternal = false;
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Determine what happened
|
|
103
|
-
const wasChecked = oldVal.includes(ctrlVal);
|
|
104
|
-
const isChecked = newVal.includes(ctrlVal);
|
|
105
|
-
|
|
106
|
-
// Scenario A: User clicked "All" (Checked it)
|
|
107
|
-
if (!wasChecked && isChecked) {
|
|
108
|
-
// Lock to prevent infinite recursion
|
|
109
|
-
el$.value.__lockedInternal = true;
|
|
110
|
-
el$.value.checkAll();
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Scenario B: User clicked "All" (Unchecked it)
|
|
115
|
-
if (wasChecked && !isChecked) {
|
|
116
|
-
el$.value.__lockedInternal = true;
|
|
117
|
-
el$.value.uncheckAll();
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Scenario C: User clicked a Sibling (Check logic)
|
|
122
|
-
const othersComplete = otherVals.every((v) =>
|
|
123
|
-
newVal.includes(v)
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
if (isChecked && !othersComplete) {
|
|
127
|
-
// "All" is checked, but a sibling is missing -> Uncheck "All"
|
|
128
|
-
el$.value.__lockedInternal = true;
|
|
129
|
-
el$.value.value = newVal.filter((v) => v !== ctrlVal);
|
|
130
|
-
} else if (!isChecked && othersComplete) {
|
|
131
|
-
// "All" is unchecked, but all siblings are there -> Check "All"
|
|
132
|
-
el$.value.__lockedInternal = true;
|
|
133
|
-
el$.value.value = [...newVal, ctrlVal];
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
return component;
|
|
142
|
-
},
|
|
143
|
-
};
|
|
144
|
-
}
|