UNPKG

ar-design

Version:

AR Design is a (react | nextjs) ui library.

742 lines (741 loc) 40.5 kB
"use client"; import "../../../assets/css/components/data-display/table/styles.css"; import { ARIcon } from "../../icons"; import Button from "../../form/button"; import Checkbox from "../../form/checkbox"; import Pagination from "../../navigation/pagination"; import React, { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, } from "react"; import Input from "../../form/input"; import Utils from "../../../libs/infrastructure/shared/Utils"; import FilterPopup from "./FilterPopup"; import { FilterOperator } from "../../../libs/infrastructure/shared/Enums"; import Select from "../../form/select"; import Grid from "../grid-system"; import THeadCell from "./THeadCell"; import { flushSync } from "react-dom"; import { createRoot } from "react-dom/client"; import PropertiesPopup from "./PropertiesPopup"; import { ExtractKey } from "./Helpers"; import Header from "./header/Header"; import TBody from "./body/TBody"; import DatePicker from "../../form/date-picker"; import { useTranslation } from "../../../libs/core/application/hooks"; const { Row, Column } = Grid; const Table = forwardRef(({ children, trackBy, title, description, data, columns, actions, rowBackgroundColor, selections, previousSelections, sortedParams, searchedParams, onEditable, onDnD, pagination, config = { isSearchable: false }, }, ref) => { // refs const _innerRef = useRef(null); const _tableWrapper = useRef(null); const _tableContent = useRef(null); const _tBody = useRef(null); const _dragItem = useRef(null); const _checkboxItems = useRef([]); const _filterCheckboxItems = useRef([]); // refs -> Search const _searchTextInputs = useRef([]); const _searchTimeOut = useRef(null); // refs -> Properties const _propertiesButton = useRef([]); // refs -> Filter const _filterButton = useRef([]); // refs -> Selection const _selectionItems = useRef([]); const lastSentRef = useRef([]); // variables const _subrowOpenAutomatically = config.subrow?.openAutomatically ?? false; const _subrowSelector = config.subrow?.selector ?? "subitems"; const _subrowButton = config.subrow?.button ?? true; // className const _tableClassName = ["ar-table", "scroll"]; // states const [selectAll, setSelectAll] = useState(false); const [showSubitems, setShowSubitems] = useState({}); // states -> Action Buttons const [createTrigger, setCreateTrigger] = useState(false); // states -> Search const [searchedText, setSearchedText] = useState(null); const [_searchedParams, setSearchedParams] = useState(null); const [checkboxSelectedParams, setCheckboxSelectedParams] = useState(null); // states -> Sort const [sortConfig, setSortConfig] = useState([]); const [sortCurrentColumn, setSortCurrentColumn] = useState(null); // states -> Properties const [openProperties, setOpenProperties] = useState(false); const [propertiesButtonCoordinate, setPropertiesButtonCoordinate] = useState({ x: 0, y: 0, }); // states -> Filter const [filterButtonCoordinate, setFilterButtonCoordinate] = useState({ x: 0, y: 0 }); const [filterPopupContent, setFilterPopupContent] = useState(null); const [filterPopupOption, setFilterPopupOption] = useState(null); const [filterPopupOptionSearchText, setFilterPopupOptionSearchText] = useState(null); // states -> Filter Fields Backup const [openFilter, setOpenFilter] = useState(false); const [filterCurrentColumn, setFilterCurrentColumn] = useState(null); const [filterCurrentDataType, setFilterCurrentDataType] = useState(null); const [filterCurrentIndex, setFilterCurrentIndex] = useState(null); // states -> Pagination const [totalRecords, setTotalRecords] = useState(0); const [currentPage, setCurrentPage] = useState(1); const [selectedPerPage, setSelectedPerPage] = useState(pagination?.perPage ?? 10); // states -> Mobil const [isMobile, setIsMobile] = useState(false); // hooks const { t } = useTranslation(String(config.locale ?? "tr")); // Dışarıdan gelen ref'i _innerRef'e bağla. useImperativeHandle(ref, () => _innerRef.current); if (config && Object.keys(config.scroll || {}).length > 0) { if (_tableContent.current && config.scroll) { if (config.scroll.maxHeight) { _tableContent.current.style.maxHeight = `${config?.scroll?.maxHeight}rem`; } } } // methods const handleScroll = useCallback(() => { if (!_tableWrapper.current) return; const wrapperRect = _tableWrapper.current.getBoundingClientRect(); const updateStickyPositions = (elements) => { elements.forEach((element) => { const leftChildren = Array.from(element.childNodes) .filter((node) => node.nodeType === Node.ELEMENT_NODE) .filter((child) => child.dataset.stickyPosition === "left"); const rightChildren = Array.from(element.childNodes) .filter((node) => node.nodeType === Node.ELEMENT_NODE) .filter((child) => child.dataset.stickyPosition === "right") .reverse(); // Calculate positions and minimize `getBoundingClientRect` calls const leftRects = leftChildren.map((child) => child.getBoundingClientRect()); const rightRects = rightChildren.map((child) => child.getBoundingClientRect()); const leftPrevious = leftRects.map((rect) => Math.abs(rect.right - wrapperRect.left)); const rightPrevious = rightRects.map((rect) => Math.abs(rect.left - wrapperRect.right)); // #region Left leftChildren.forEach((child, index) => { const prevLeft = index > 0 ? leftPrevious[index - 1] : 0; if (index > 0) { const childLeft = leftRects[index].left - wrapperRect.left; if (Math.floor(childLeft) === Math.floor(prevLeft)) { if (!child.classList.contains("active-sticky")) child.classList.add("active-sticky"); } else child.classList.remove("active-sticky"); child.style.left = `${prevLeft}px`; } else child.classList.add("sticky"); if (child.nodeName === "TD") child.style.zIndex = `5`; }); // #endregion // #region Right rightChildren.forEach((child, index) => { const prevRight = index > 0 ? rightPrevious[index - 1] : 0; if (index > 0) { const childRight = Math.abs(rightRects[index].right - wrapperRect.right); if (Math.floor(childRight) === Math.floor(prevRight)) { if (!child.classList.contains("active-sticky")) child.classList.add("active-sticky"); } else child.classList.remove("active-sticky"); child.style.right = `${prevRight}px`; } else child.classList.add("sticky"); }); // #endregion }); }; const theadElements = _tableWrapper.current.querySelectorAll("table > thead > tr"); const tbodyElements = _tableWrapper.current.querySelectorAll("table > tbody > tr"); requestAnimationFrame(() => { updateStickyPositions(theadElements); updateStickyPositions(tbodyElements); }); }, []); const handleResize = useMemo(() => { return (_) => { setIsMobile(window.innerWidth <= 768); }; }, []); const handleSearch = useCallback((name, value, dataType) => { const operator = filterPopupOption?.key == name ? filterPopupOption.option?.value : FilterOperator.Contains; if (config.isServerSide) { if (_searchTimeOut.current) clearTimeout(_searchTimeOut.current); _searchTimeOut.current = setTimeout(() => { setSearchedParams((prev) => ({ ...prev, [name]: { value: value, operator: operator }, })); if (pagination) pagination.onChange?.(1, selectedPerPage); }, dataType === "date" ? 0 : 750); } else { setSearchedText((prev) => { const _state = { ...prev }; if (value === "") { delete _state[name]; // Key'i siliyoruz } else { _state[name] = { value: value, operator: operator }; // Yeni değeri ekliyoruz } return _state; }); } setCurrentPage(1); }, [filterPopupOption]); const handleCheckboxChange = useCallback(async (event) => { event.stopPropagation(); const { name, value, checked } = event.target; setCheckboxSelectedParams((prev) => { const prevFilters = prev?.[name] || []; const updatedSet = new Set(prevFilters.map((f) => String(f.value))); checked ? updatedSet.add(value) : updatedSet.delete(value); const updatedArray = Array.from(updatedSet).map((v) => ({ value: v, operator: FilterOperator.Equals, // Checkbox’lar genelde “Equals” anlamındadır. })); return { ...prev, ...(updatedArray.length > 0 ? { [name]: updatedArray } : { [name]: [] }), }; }); }, []); const handleFilterPopupContent = (c, dataType, index) => { const key = ExtractKey(c.key); if (!key) return; const value = Array.isArray(searchedText?.[key]) ? "" // veya ihtiyacına göre birleştirme yap: searchedText[key].map(v => v.value).join(", "). : searchedText?.[key]?.value; const handleChange = (value) => { const input = _searchTextInputs.current[index ?? 0]; if (input) { const event = new Event("input", { bubbles: true }); input.value = value; input.dispatchEvent(event); } }; setFilterPopupContent(() => { switch (dataType) { case "string": case "number": return (React.createElement(Row, null, React.createElement(Column, { size: 12 }, React.createElement(Select, { value: filterOption.find((x) => x.value === filterPopupOption?.option?.value && filterPopupOption.key === c.key) ?? filterOption[0], options: filterOption, onChange: (option) => { setFilterPopupOption({ key: c.key, option: option }); }, placeholder: t("Table.Filters.Where.Input.Placeholder") })), React.createElement(Column, { size: 12 }, React.createElement(Input, { value: value ?? "", onChange: (event) => handleChange(event.target.value), placeholder: t("Table.Filters.Search.Input.Placeholder") })))); case "object": case "boolean": return (React.createElement(Row, null, React.createElement(Column, { size: 12 }, React.createElement(Input, { value: value ?? "", onChange: (event) => setFilterPopupOptionSearchText(event.target.value), placeholder: t("Table.Filters.Search.Input.Placeholder") })), React.createElement(Column, { size: 12 }, c.filters ?.filter((filter) => filter.text.toLocaleLowerCase().includes(filterPopupOptionSearchText?.toLocaleLowerCase() ?? "")) ?.map((filter, fIndex) => { const name = typeof c.key !== "object" ? String(c.key) : String(c.key.field); return (React.createElement("div", null, React.createElement(Checkbox, { ref: (element) => { if (!element) return; _filterCheckboxItems.current[fIndex] = element; }, variant: "filled", color: "green", label: filter.text, name: name, value: filter.value, checked: Array.isArray(checkboxSelectedParams?.[name]) && checkboxSelectedParams?.[name]?.some((f) => String(f.value) === String(filter.value)), onChange: async (event) => await handleCheckboxChange(event) }))); })))); default: return React.createElement(React.Fragment, null); } }); }; // Derinlemesine arama yapmak için özyinelemeli bir fonksiyon olarak kullanılmaktadır. const deepSearch = (item, searchedText) => { if (!searchedText || Object.keys(searchedText).length === 0) return true; const applyOperator = (value, filter) => { if (Array.isArray(value)) { // Array içindeki herhangi bir öğe eşleşirse true dön return value.some((item) => applyOperator(item, filter)); } if (typeof value === "object" && value !== null) { // Eğer obje ise, içindeki değerlerden biri eşleşirse true dön return Object.values(value).some((v) => applyOperator(v, filter)); } const text = String(value ?? "").toLocaleLowerCase(); const searchText = String(filter.value ?? "").toLocaleLowerCase(); switch (filter.operator) { case FilterOperator.Contains: return text.includes(searchText); case FilterOperator.DoesNotContains: return !text.includes(searchText); case FilterOperator.Equals: return text === searchText; case FilterOperator.DoesNotEquals: return text !== searchText; case FilterOperator.BeginsWith: return text.startsWith(searchText); case FilterOperator.EndsWith: return text.endsWith(searchText); case FilterOperator.Blank: return text.trim() === ""; case FilterOperator.NotBlank: return text.trim() !== ""; default: return false; } }; return Object.entries(searchedText).every(([key, param]) => { const _itemValue = item[key]; if (Array.isArray(param)) { if (param.length === 0) return true; return param.some((filter) => applyOperator(_itemValue, filter)); } else { return applyOperator(_itemValue, param); } }); // Eğer değer bir sayı veya string ise, aranan metinle eşleşip eşleşmediğini kontrol ediyoruz. // return Object.entries(searchedText).every(([key, param]) => { // const _itemValue = item[key as keyof typeof item]; // if (typeof _itemValue === "number" || typeof _itemValue === "string" || typeof _itemValue === "boolean") { // if (Array.isArray(param)) { // if (param.length === 0) return true; // else return param.some((v) => _itemValue.toString().toLocaleLowerCase().includes(v.toLocaleLowerCase())); // } // return _itemValue // .toString() // .toLocaleLowerCase() // .includes(param.toLocaleLowerCase() ?? ""); // } // if (typeof _itemValue === "object") { // if (Array.isArray(param)) { // if (param.length === 0) return true; // else { // return param.some((v) => { // if (Array.isArray(_itemValue)) { // return Object.values(_itemValue?.[0 as keyof typeof _itemValue] ?? {}).some((objValue) => { // return String(objValue).toLocaleLowerCase().includes(String(v).toLocaleLowerCase()); // }); // } // }); // } // } // } // if (Array.isArray(_itemValue)) { // console.log("Buradasın", _itemValue); // } // return false; // }); }; const openAllSubrowsRecursively = (data, parentKey = "") => { let result = {}; data.forEach((item) => { const id = trackBy?.(item); const key = parentKey ? `${parentKey}.${id}` : `${id}`; const subitems = item[_subrowSelector]; if (subitems && Array.isArray(subitems) && subitems.length > 0) { const nested = openAllSubrowsRecursively(subitems, key); result[key] = true; result = { ...result, ...nested }; } }); return result; }; const getData = useMemo(() => { let _data = [...data]; if (_subrowOpenAutomatically) setShowSubitems(openAllSubrowsRecursively(data)); if (searchedText && Object.keys(searchedText).length > 0) { _data = _data.filter((item) => deepSearch(item, searchedText)); setTotalRecords(_data.length); } else { setTotalRecords(data.length); } // Sorting... if (sortConfig.length > 0 && !config.isServerSide) { _data.sort((a, b) => { for (const config of sortConfig) { const aValue = a[config.key]; const bValue = b[config.key]; if (aValue < bValue) return config.direction === "asc" ? -1 : 1; if (aValue > bValue) return config.direction === "asc" ? 1 : -1; } return 0; }); } if (pagination && !config.isServerSide) { const indexOfLastRow = currentPage * selectedPerPage; const indexOfFirstRow = indexOfLastRow - selectedPerPage; _data = _data.slice(indexOfFirstRow, indexOfLastRow); } handleScroll(); return _data; }, [data, searchedText, currentPage, selectedPerPage, sortConfig, config.isServerSide]); // useEffects useEffect(() => { if (!previousSelections || previousSelections.length === 0) { _selectionItems.current = []; return; } const validSelections = data.filter((item) => previousSelections.some((selected) => trackBy?.(selected) === trackBy?.(item))); // Gereksiz overwrite’i engelle. if (!Utils.DeepEqual(_selectionItems.current, validSelections)) { _selectionItems.current = validSelections; } }, [previousSelections, data, trackBy]); useEffect(() => { if (config?.isServerSide && sortedParams) { const sortRecord = {}; sortConfig?.forEach((s) => { if (s.direction) sortRecord[String(s.key)] = s.direction; }); const query = new URLSearchParams(sortRecord); sortedParams(sortConfig ?? [], query.toString()); } }, [sortConfig]); useEffect(() => { if (config?.isServerSide && searchedParams) { const searchRecord = {}; Object.entries(_searchedParams ?? {}).forEach(([key, value]) => { if (Array.isArray(value)) { // Çoklu filtre değerleri varsa virgülle birleştir. searchRecord[key] = value.map((v) => v.value).join(","); } else if (value && typeof value === "object") { searchRecord[key] = String(value.value); } }); const query = new URLSearchParams(searchRecord); columns.forEach((column) => { const key = column.key; const filterValue = _searchedParams?.[key]; const filterArray = Array.isArray(filterValue) ? filterValue : filterValue ? [filterValue] : []; const getParamsLength = column.filters?.length ?? 0; const searchedParamLength = filterArray.length; if (getParamsLength === searchedParamLength) { query.delete(column.key); } }); searchedParams(_searchedParams, query.toString(), filterPopupOption?.option?.value); } }, [_searchedParams]); useEffect(() => { if (!checkboxSelectedParams) return; if (config.isServerSide) { if (_searchTimeOut.current) clearTimeout(_searchTimeOut.current); setSearchedParams((prev) => ({ ...prev, ...checkboxSelectedParams })); } else { setSearchedText((prev) => ({ ...prev, ...checkboxSelectedParams })); } setCurrentPage(1); if (pagination) pagination.onChange?.(1, selectedPerPage); }, [checkboxSelectedParams]); useEffect(() => { if (typeof selections !== "function") return; const payload = _selectionItems.current.map((item) => ({ ...item, trackByValue: trackBy?.(item), })); if (!Utils.DeepEqual(payload, lastSentRef.current)) { lastSentRef.current = payload; selections(payload); } }, [selections, trackBy]); useEffect(() => { // Filter Content alanı re-render işlemi. if (filterCurrentColumn && filterCurrentDataType) { handleFilterPopupContent(filterCurrentColumn, filterCurrentDataType, filterCurrentIndex); } }, [checkboxSelectedParams, filterPopupOption, filterPopupOptionSearchText]); useLayoutEffect(() => { // @DND if (!onDnD || !_tBody.current || data.length === 0) return; _tBody.current.childNodes.forEach((item) => { const _item = item; // Events _item.ondragstart = (event) => { const dragItem = event.currentTarget; _dragItem.current = dragItem; dragItem.classList.add("drag-item"); if (event.dataTransfer) { // 1. Geçici bir kapsayıcı oluştur const shadowContainer = document.createElement("div"); shadowContainer.style.position = "absolute"; shadowContainer.style.top = "-9999px"; shadowContainer.style.left = "-9999px"; document.body.appendChild(shadowContainer); if (config.dnd?.renderItem) { // 2a. React Node varsa: createRoot ile render et const root = createRoot(shadowContainer); // flushSync kullanıyoruz çünkü setDragImage çağrılmadan önce // DOM'un hemen güncellenmesi gerekiyor. flushSync(() => { root.render(config.dnd?.renderItem); }); } else { // 2b. React Node yoksa: Varsayılan HTML string shadowContainer.innerHTML = ` <div class="ar-dnd-shadow" style="background: white; padding: 10px; border: 1px solid #ccc;"> <i class="bi bi-gear-wide-connected"></i> <span>Dragging...</span> </div> `; } // 3. Tarayıcıya bu elementi sürükleme görseli yapmasını söyle // (0, 0) koordinatları mouse'un görselin neresinde duracağını belirler event.dataTransfer.setDragImage(shadowContainer, 20, 20); // 4. Temizlik: Görsel hafızaya alındıktan sonra DOM'dan kaldırabiliriz // Bir sonraki event loop'ta silmek en güvenlisidir setTimeout(() => { document.body.removeChild(shadowContainer); }, 0); } }; _item.ondragover = (event) => { event.preventDefault(); const overItem = event.currentTarget; const rect = overItem.getBoundingClientRect(); // Otomatik scroll. if (rect.top < 250) window.scrollBy(0, -20); if (rect.bottom > window.innerHeight - 150) window.scrollBy(0, 20); // Gerçek taşıma işlemi. if (_dragItem.current !== overItem) { if (_tBody.current && _dragItem.current) { const dragItemIndex = [..._tBody.current.children].indexOf(_dragItem.current); const dropItemIndex = [..._tBody.current.children].indexOf(overItem); if (dragItemIndex === -1 || dropItemIndex === -1) return; _tBody.current.insertBefore(_dragItem.current, dragItemIndex < dropItemIndex ? overItem.nextSibling : overItem); const movedItem = data.splice(dragItemIndex, 1)[0]; if (movedItem) { data.splice(dropItemIndex, 0, movedItem); onDnD?.(data); } } } }; _item.ondragend = (event) => { const item = event.currentTarget; item.classList.remove("drag-item"); item.classList.add("end-item"); setTimeout(() => { item.classList.remove("end-item"); if (item.classList.length === 0) item.removeAttribute("class"); }, 1000); }; }); _tBody.current.ondragover = (event) => event.preventDefault(); return () => { if (!_tBody.current) return; _tBody.current.childNodes.forEach((item) => { const _item = item; _item.ondragstart = null; _item.ondragover = null; _item.ondragend = null; }); _tBody.current.ondragover = null; }; }, [data]); useLayoutEffect(() => { if (!pagination?.currentPage) return; setTimeout(() => handleScroll(), 0); setCurrentPage(pagination?.currentPage ?? 1); }, [pagination?.currentPage]); useLayoutEffect(() => { setCurrentPage(1); setTimeout(() => handleScroll(), 0); }, [selectedPerPage]); useEffect(() => { if (typeof selections !== "function" && config.validation) { const updatedData = data.map((item) => { if (!("trackByValue" in item) && trackBy) { return { ...item, trackByValue: trackBy(item) }; } return item; }); config.validation?.getChangeData?.(updatedData); } }, [createTrigger]); useEffect(() => { setIsMobile(window.innerWidth <= 768); window.addEventListener("resize", handleResize); if (typeof selections !== "function" && config.validation) { config.validation.getChangeData?.(data.map((d) => ({ ...d, trackByValue: trackBy?.(d) })) ?? []); } return () => { window.removeEventListener("resize", handleResize); }; }, []); const filterOption = [ { value: FilterOperator.Contains, text: t("Table.Filters.Where.Input.Item.1.Text") }, { value: FilterOperator.DoesNotContains, text: t("Table.Filters.Where.Input.Item.2.Text") }, { value: FilterOperator.Equals, text: t("Table.Filters.Where.Input.Item.3.Text") }, { value: FilterOperator.DoesNotEquals, text: t("Table.Filters.Where.Input.Item.4.Text") }, { value: FilterOperator.BeginsWith, text: t("Table.Filters.Where.Input.Item.5.Text") }, { value: FilterOperator.EndsWith, text: t("Table.Filters.Where.Input.Item.6.Text") }, { value: FilterOperator.Blank, text: t("Table.Filters.Where.Input.Item.7.Text") }, { value: FilterOperator.NotBlank, text: t("Table.Filters.Where.Input.Item.8.Text") }, ]; return (React.createElement("div", { ref: _tableWrapper, className: _tableClassName.map((c) => c).join(" ") }, (title || description || actions || React.Children.count(children) > 0) && (React.createElement(Header, { states: { createTrigger: { get: createTrigger, set: setCreateTrigger } }, title: title, description: description, actions: actions })), React.createElement("div", { ref: _tableContent, className: "content", onScroll: handleScroll }, React.createElement("table", { ref: _innerRef }, React.createElement("thead", null, React.createElement("tr", { key: "selection" }, data.some((item) => _subrowSelector in item) && _subrowButton && (React.createElement("td", { style: { width: 0, minWidth: 0 } })), selections && (React.createElement("th", { className: "selection-col sticky-left", "data-sticky-position": "left", style: { bottom: 0 } }, React.createElement(Checkbox, { variant: "filled", color: "green", checked: selectAll, onChange: (event) => { if (_checkboxItems.current.length > 0) { setSelectAll(event.target.checked); _checkboxItems.current.forEach((item) => { if (item) { if (item.checked !== event.target.checked) item.click(); } }); } } }))), React.createElement(THeadCell, { refs: { propertiesButton: _propertiesButton, }, states: { open: { get: openProperties, set: setOpenProperties }, sort: { get: sortConfig, set: setSortConfig }, sortCurrentColumn: { set: setSortCurrentColumn }, propertiesButtonCoordinate: { set: setPropertiesButtonCoordinate }, }, methods: { handleScroll }, columns: columns, config: config })), config?.isSearchable && (React.createElement("tr", { key: "isSearchable" }, selections && (React.createElement("th", { key: `column-selections`, className: "selection-col sticky-left", "data-sticky-position": "left" })), columns.map((c, cIndex) => { let _className = []; const key = typeof c.key !== "object" ? String(c.key) : String(c.key.field); const csrValue = Array.isArray(searchedText?.[key]) ? "" // veya ihtiyacına göre birleştirme yap: searchedText[key].map(v => v.value).join(", "). : searchedText?.[key]?.value; const ssrValue = Array.isArray(_searchedParams?.[key]) ? "" // veya ihtiyacına göre birleştirme yap: _searchedParams[key].map(v => v.value).join(", "). : _searchedParams?.[key]?.value; if (c.config?.sticky) _className.push(`sticky-${c.config.sticky}`); if (c.config?.alignContent) { _className.push(`align-content-${c.config.alignContent}`); } return (React.createElement("th", { key: `column-${cIndex}`, ...(_className.length > 0 && { className: `${_className.map((c) => c).join(" ")}`, }), ...(c.config?.sticky && { "data-sticky-position": c.config.sticky, }) }, c.key && (React.createElement("div", { className: "filter-field" }, c.filterDataType === "date" ? (React.createElement(DatePicker, { value: (config.isServerSide ? ssrValue : csrValue) ?? "", name: key, onClick: () => { handleScroll(); }, onChange: (value) => handleSearch(key, value, c.filterDataType), style: { height: "2rem" }, config: { isClock: true, isFooterButton: true, locale: config.locale }, disabled: !c.key || !!c.filters })) : (React.createElement(React.Fragment, null, React.createElement(Input, { ref: (element) => { if (!element) return; _searchTextInputs.current[cIndex] = element; }, variant: c.key && !c.filters ? "outlined" : "filled", style: { height: "2rem" }, value: (config.isServerSide ? ssrValue : csrValue) ?? "", name: key, onClick: () => { handleScroll(); }, onInput: (event) => handleSearch(event.currentTarget.name, event.currentTarget.value), disabled: !c.key || !!c.filters }), React.createElement("span", { ref: (element) => { if (!element) return; _filterButton.current[cIndex] = element; }, onClick: (event) => { event.preventDefault(); event.stopPropagation(); // Temizlik... setFilterPopupOptionSearchText(""); const rect = event.currentTarget.getBoundingClientRect(); const screenCenterX = window.innerWidth / 2; // const screenCenterY = window.innerHeight / 2; const coordinateX = rect.x > screenCenterX ? rect.x + rect.width - 225 : rect.x; const coordinateY = rect.y + rect.height; // data içindeki alanların tiplerini bulmak için kullanılmaktadır const getDataFirstItem = { ...data[0] }; const key = typeof c.key !== "object" ? String(c.key) : String(c.key.field); const getValueByKey = getDataFirstItem[key]; let dataType = typeof getValueByKey; if (getValueByKey == null) dataType = "string"; setFilterButtonCoordinate({ x: coordinateX, y: coordinateY }); setFilterCurrentColumn(c); setFilterCurrentDataType(c.filterDataType ?? dataType); setFilterCurrentIndex(cIndex); setOpenFilter(true); handleFilterPopupContent(c, c.filterDataType ?? dataType, cIndex); handleScroll(); } }, React.createElement(Button, { variant: "borderless", icon: { element: React.createElement(ARIcon, { size: 24, icon: "Filter", fill: "var(--dark)", strokeWidth: 0 }), } })))))))); })))), React.createElement("tbody", { ref: _tBody }, React.createElement(TBody, { data: getData, columns: columns, refs: { _checkboxItems: _checkboxItems, _selectionItems: _selectionItems }, states: { setSelectAll: { get: selectAll, set: setSelectAll }, showSubitems: { get: showSubitems, set: setShowSubitems }, }, methods: { trackBy: trackBy, selections: selections, onDnD: onDnD, onEditable: onEditable, rowBackgroundColor: rowBackgroundColor, }, config: config })))), React.createElement(FilterPopup, { refs: { tableContent: _tableContent, buttons: _filterButton, }, states: { open: { get: openFilter, set: setOpenFilter }, }, coordinate: filterButtonCoordinate }, filterPopupContent), config.isProperties && (React.createElement(PropertiesPopup, { refs: { tableContent: _tableContent, buttons: _propertiesButton, }, states: { open: { get: openProperties, set: setOpenProperties }, sort: { get: sortConfig, set: setSortConfig, currentColumn: sortCurrentColumn }, }, methods: { handleScroll }, coordinate: propertiesButtonCoordinate, config: config })), React.createElement("div", { className: "footer" }, React.createElement("span", null, isMobile ? (React.createElement(React.Fragment, null, React.createElement("strong", null, (currentPage - 1) * selectedPerPage + 1, " -", " ", Math.min(currentPage * selectedPerPage, pagination?.totalRecords || getData.length), " of", " ", pagination?.totalRecords || getData.length))) : (t("Table.Pagination.Information.Text", (currentPage - 1) * selectedPerPage + 1, Math.min(currentPage * selectedPerPage, pagination?.totalRecords || getData.length), pagination?.totalRecords || getData.length))), pagination && (React.createElement(Pagination, { totalRecords: config.isServerSide ? pagination.totalRecords : (totalRecords ?? 0), currentPage: currentPage, perPage: selectedPerPage, onChange: (currentPage, perPage) => { setCurrentPage(currentPage); setSelectedPerPage(perPage); pagination.onChange?.(currentPage, perPage); setTimeout(() => handleScroll(), 0); } }))))); }); export default memo(Table, (prevProps, nextProps) => { const data = Utils.DeepEqual(prevProps.data, nextProps.data); const columns = Utils.DeepEqual(prevProps.columns, nextProps.columns); const actions = Utils.DeepEqual(prevProps.actions, nextProps.actions); const previousSelections = Utils.DeepEqual(prevProps.previousSelections, nextProps.previousSelections); const pagination = Utils.DeepEqual(prevProps.pagination, nextProps.pagination); return data && columns && actions && previousSelections && pagination; });