UNPKG

@craftercms/studio-ui

Version:

Services, components, models & utils to build CrafterCMS authoring extensions.

158 lines (156 loc) 5.97 kB
/* * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Copyright (C) 2007-2023 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { createLookupTable } from '../../utils/object'; function intersection(listItemsA, listItemsB) { return listItemsA.filter((itemA) => listItemsB.find((itemB) => itemA.id === itemB.id)); } export function excludeCommonItems(listItemsA, listItemsB) { return listItemsA.filter((itemA) => !listItemsB.find((itemB) => itemA.id === itemB.id)); } export const filterTransferListItemsByKeyword = (items, keyword) => { var _a; return (_a = items === null || items === void 0 ? void 0 : items.filter((item) => `${item.title}${item.subtitle}`.toLowerCase().includes(keyword.toLowerCase()))) !== null && _a !== void 0 ? _a : null; }; export const useTransferListState = () => { const [sourceItems, setSourceItems] = useState([]); const [targetItems, setTargetItems] = useState([]); const [checkedList, setCheckedList] = useState({}); const [sourceFilterKeyword, setSourceFilterKeyword] = useState(''); const [targetFilterKeyword, setTargetFilterKeyword] = useState(''); // Client-side filtered items const filteredSourceItems = filterTransferListItemsByKeyword(sourceItems, sourceFilterKeyword); const filteredTargetItems = filterTransferListItemsByKeyword(targetItems, targetFilterKeyword); const [itemsLookup, setItemsLookup] = useState({}); const itemsLookupRef = useRef({}); itemsLookupRef.current = itemsLookup; useEffect(() => { setItemsLookup( Object.assign( Object.assign(Object.assign({}, itemsLookupRef.current), createLookupTable(sourceItems)), createLookupTable(targetItems) ) ); }, [sourceItems, targetItems]); const isAllChecked = useCallback( (items) => { return (items === null || items === void 0 ? void 0 : items.length) ? !items.some( (item) => !Object.keys(checkedList).find(function (checked) { return checked === item.id && checkedList[checked]; }) ) : false; }, [checkedList] ); const getChecked = (items) => { return intersection( Object.keys(checkedList) .filter((key) => checkedList[key]) .map((id) => itemsLookup[id]), items ); }; const disableAdd = getChecked(sourceItems).length === 0; const disableRemove = getChecked(targetItems).length === 0; const onItemClicked = (item) => { if (checkedList[item.id]) { setCheckedList(Object.assign(Object.assign({}, checkedList), { [item.id]: false })); } else { setCheckedList(Object.assign(Object.assign({}, checkedList), { [item.id]: true })); } }; const onCheckAllClicked = (items, checked) => { const nextCheckedList = {}; items.forEach((item) => { nextCheckedList[item.id] = checked; }); setCheckedList(Object.assign(Object.assign({}, checkedList), nextCheckedList)); }; const addToTarget = () => { const nextCheckedList = {}; const leftCheckedItems = getChecked(sourceItems); if (leftCheckedItems.length) { leftCheckedItems.forEach((item) => (nextCheckedList[item.id] = false)); setCheckedList(Object.assign(Object.assign({}, checkedList), nextCheckedList)); setSourceItems(excludeCommonItems(sourceItems, leftCheckedItems)); setTargetItems([...targetItems, ...leftCheckedItems]); } }; const removeFromTarget = () => { const nextCheckedList = {}; const rightCheckedItems = getChecked(targetItems); if (rightCheckedItems.length) { rightCheckedItems.forEach((item) => (nextCheckedList[item.id] = false)); setCheckedList(Object.assign(Object.assign({}, checkedList), nextCheckedList)); setTargetItems(excludeCommonItems(targetItems, rightCheckedItems)); setSourceItems([...sourceItems, ...rightCheckedItems]); } }; const sourceItemsAllChecked = useMemo(() => { return isAllChecked(filteredSourceItems); }, [isAllChecked, filteredSourceItems]); const targetItemsAllChecked = useMemo(() => { return isAllChecked(filteredTargetItems); }, [isAllChecked, filteredTargetItems]); return { sourceItems, setSourceItems, sourceFilterKeyword, setSourceFilterKeyword, filteredSourceItems, targetItems, setTargetItems, targetFilterKeyword, setTargetFilterKeyword, filteredTargetItems, checkedList, setCheckedList, onItemClicked, isAllChecked, onCheckAllClicked, getChecked, disableAdd, disableRemove, sourceItemsAllChecked, targetItemsAllChecked, addToTarget, removeFromTarget }; };