checkbox-tree-sync
Version:
A lightweight library for checkbox tree synchronization
2 lines (1 loc) • 3.66 kB
JavaScript
(function(r,i){typeof exports=="object"&&typeof module<"u"?i(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],i):(r=typeof globalThis<"u"?globalThis:r||self,i(r["checkbox-tree-sync"]={},r.react))})(this,function(r,i){"use strict";var d=(h=>(h.Indeterminate="indeterminate",h.Checked="checked",h))(d||{});class k{constructor(e){this.params=e,this.flattenData=this.makeDataFlat(e.data),this.state=e.state??{}}flattenData;variant={};state={};getCheckboxesModel(){return{checkboxes:this.createSubCheckboxesModel(this.params.data)}}pickAll(){const e={};Object.keys(this.flattenData).forEach(t=>{e[t]=!0}),this.handleChangeState(e)}makeDataFlat(e,t){const{getCheckboxId:a,getSubCheckboxes:s}=this.params,n={};return e.forEach(o=>{const c=s(o)??[],l=a(o),u=c.map(a);if(n[l]={id:l,data:o,children:u,parentId:t},c.length>0){const C=this.makeDataFlat(c,l);Object.assign(n,C)}}),n}pickCheckboxParents(e){const t={};let a=e;for(;a&&this.flattenData[a]?.parentId;)a=this.flattenData[a].parentId,t[a]=!0;return t}getCheckboxChildren(e){let t=this.flattenData[e]?.children??[];const a=t.flatMap(s=>this.getCheckboxChildren(s));return t.concat(a)}pickCheckboxChildren(e){const t={};return this.getCheckboxChildren(e).forEach(s=>{t[s]=!0}),t}removeCheckboxParents(e,t){const a={...t};let s=this.flattenData[e].parentId;for(;s;){const n=this.flattenData[s];n.children.some(c=>a[c])?s=void 0:(delete a[s],s=n.parentId)}return a}removeCheckboxChildren(e,t){const a={...t};return this.getCheckboxChildren(e).forEach(n=>{delete a[n]}),a}toggleCheckbox(e,t){const a={...this.state};if(t)return Object.assign(a,this.pickCheckboxParents(e),this.pickCheckboxChildren(e),{[e]:!0}),a;delete a[e];const s=this.removeCheckboxParents(e,a);return this.removeCheckboxChildren(e,s)}createCheckboxModel(e){const t=this.params.getCheckboxId(e);return{id:t,getIsChecked:()=>!!this?.state?.[t],getVariant:()=>this.variant[t]?.type??d.Checked,getToggleHandler:()=>()=>{const a=this.state?.[t],s=this.toggleCheckbox(t,!a);this.handleChangeState(s)}}}createSubCheckboxesModel(e){return e.map(t=>{const a=this.createCheckboxModel(t),s=this.params.getSubCheckboxes(t)??[],n=this.createSubCheckboxesModel(s);return{...a,subCheckboxes:n}})}handleChangeState(e){this.params?.onStateChange?this.params.onStateChange?.(e):this.updateState(e)}updateVariant(e){this.variant=this.params?.getCheckboxVariantModel?.({data:this.params.data,state:e,getCheckboxId:this.params.getCheckboxId,getSubCheckboxes:this.params.getSubCheckboxes})??{}}updateParams(e){e.data&&this.params?.data!==e.data&&(this.flattenData=this.makeDataFlat(e.data)),this.params=e}updateState(e){e!==void 0&&this.params.state!==e&&(this.updateVariant(e),this.state=e)}}const b=()=>({data:h,state:e,getSubCheckboxes:t,getCheckboxId:a})=>{const s={};return h.forEach(n=>{const o=t(n)??[],c=a(n);if(o&&o.length){const l=b()({data:o,state:e,getCheckboxId:a,getSubCheckboxes:t});Object.assign(s,l);const u=Object.values(l).every(C=>C.checked);c&&(s[c]={checked:u,type:u?d.Checked:d.Indeterminate})}else c&&(s[c]={checked:e[c],type:d.Checked})}),s},f=({controlled:h,default:e})=>{const{current:t}=i.useRef(h!==void 0),[a,s]=i.useState(e),n=t?h:a,o=i.useCallback(c=>{t||s(c)},[t]);return[n,o]},g=({state:h,...e})=>{const[t,a]=f({controlled:h,default:{}}),s=i.useRef();return s.current?(s.current.updateParams(e),s.current.updateState(t)):s.current=new k({...e,state:t,onStateChange:n=>{e.onStateChange?.(n),a(n)}}),{checkBoxTreeSync:s.current}};r.CheckboxTreeSync=k,r.CheckboxVariantEnum=d,r.getCheckboxVariantModel=b,r.useCheckboxTreeSync=g,Object.defineProperty(r,Symbol.toStringTag,{value:"Module"})});