es-grid-template 1.3.1 → 1.3.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 (39) hide show
  1. package/es/grid-component/CheckboxFilter.js +4 -0
  2. package/es/grid-component/CheckboxFilter2.d.ts +20 -0
  3. package/es/grid-component/CheckboxFilter2.js +248 -0
  4. package/es/grid-component/ContextMenu.js +1 -0
  5. package/es/grid-component/InternalTable.js +37 -3
  6. package/es/grid-component/TableGrid.d.ts +3 -0
  7. package/es/grid-component/TableGrid.js +69 -7
  8. package/es/grid-component/hooks/columns/index.js +14 -45
  9. package/es/grid-component/hooks/content/HeaderContent.js +54 -58
  10. package/es/grid-component/hooks/useColumns.js +22 -8
  11. package/es/grid-component/hooks/utils.d.ts +8 -0
  12. package/es/grid-component/hooks/utils.js +257 -1
  13. package/es/grid-component/number-range/index.d.ts +10 -0
  14. package/es/grid-component/number-range/index.js +59 -0
  15. package/es/grid-component/table/Grid.d.ts +3 -0
  16. package/es/grid-component/table/GridEdit.js +281 -62
  17. package/es/grid-component/table/Group.d.ts +1 -0
  18. package/es/grid-component/table/Group.js +1 -1
  19. package/es/grid-component/type.d.ts +2 -1
  20. package/lib/grid-component/CheckboxFilter.js +4 -0
  21. package/lib/grid-component/CheckboxFilter2.d.ts +20 -0
  22. package/lib/grid-component/CheckboxFilter2.js +257 -0
  23. package/lib/grid-component/ContextMenu.js +1 -0
  24. package/lib/grid-component/InternalTable.js +31 -2
  25. package/lib/grid-component/TableGrid.d.ts +3 -0
  26. package/lib/grid-component/TableGrid.js +67 -7
  27. package/lib/grid-component/hooks/columns/index.js +14 -45
  28. package/lib/grid-component/hooks/content/HeaderContent.js +53 -55
  29. package/lib/grid-component/hooks/useColumns.js +22 -8
  30. package/lib/grid-component/hooks/utils.d.ts +8 -0
  31. package/lib/grid-component/hooks/utils.js +270 -3
  32. package/lib/grid-component/number-range/index.d.ts +10 -0
  33. package/lib/grid-component/number-range/index.js +67 -0
  34. package/lib/grid-component/table/Grid.d.ts +3 -0
  35. package/lib/grid-component/table/GridEdit.js +281 -62
  36. package/lib/grid-component/table/Group.d.ts +1 -0
  37. package/lib/grid-component/table/Group.js +1 -1
  38. package/lib/grid-component/type.d.ts +2 -1
  39. package/package.json +109 -108
@@ -1,15 +1,20 @@
1
- import _extends from "@babel/runtime/helpers/esm/extends";
2
- import React, { Fragment, useState } from "react";
1
+ import React, { Fragment } from "react";
3
2
  import classnames from "classnames";
4
- import { useFloating, autoUpdate, offset, flip, shift, useHover, useFocus, useDismiss, useRole, useInteractions, FloatingPortal
5
- // useClick
6
- } from "@floating-ui/react";
7
- import styled from "styled-components";
3
+
4
+ // import styled from "styled-components";
8
5
  import { getTemplate } from "../utils";
9
- const TooltipStyle = styled.div.withConfig({
10
- displayName: "TooltipStyle",
11
- componentId: "es-grid-template__sc-ibhq66-0"
12
- })(["width:max-content;background-color:#444;color:white;font-size:90%;padding:4px 8px;border-radius:4px;opacity:0.9;z-index:9999;max-width:450px;"]);
6
+ // const TooltipStyle = styled.div`
7
+ // width: max-content;
8
+ // background-color: #444;
9
+ // color: white;
10
+ // font-size: 90%;
11
+ // padding: 4px 8px;
12
+ // border-radius: 4px;
13
+ // opacity: 0.9;
14
+ // z-index: 9999;
15
+ // max-width: 450px;
16
+ // `
17
+
13
18
  const HeaderContent = props => {
14
19
  const {
15
20
  t
@@ -26,54 +31,45 @@ const HeaderContent = props => {
26
31
  const tooltip = React.useMemo(() => {
27
32
  return headerTooltip ?? columnGroupText ?? headerText;
28
33
  }, [columnGroupText, headerText, headerTooltip]);
29
- const [isOpen, setIsOpen] = useState(false);
30
- const {
31
- refs,
32
- floatingStyles,
33
- context
34
- } = useFloating({
35
- open: isOpen,
36
- onOpenChange: setIsOpen,
37
- placement: "top",
38
- whileElementsMounted: autoUpdate,
39
- middleware: [offset(5), flip({
40
- fallbackAxisSideDirection: "start"
41
- }), shift()]
42
- });
43
- const hover = useHover(context, {
44
- move: false
45
- });
46
- const focus = useFocus(context);
47
- const dismiss = useDismiss(context);
48
- const role = useRole(context, {
49
- role: "tooltip"
50
- });
51
- const {
52
- getReferenceProps,
53
- getFloatingProps
54
- } = useInteractions([hover, focus, dismiss, role]);
55
- return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", _extends({
56
- ref: refs.setReference
57
- }, getReferenceProps(), {
58
- tabIndex: -1,
59
- style: {
60
- flex: 1,
61
- overflow: 'hidden',
62
- textOverflow: 'ellipsis',
63
- wordBreak: 'keep-all'
64
- }
34
+ //
35
+ //
36
+ // const [isOpen, setIsOpen] = useState(false)
37
+ //
38
+ // const { refs, floatingStyles, context } = useFloating({
39
+ // open: isOpen,
40
+ // onOpenChange: setIsOpen,
41
+ // placement: "top",
42
+ // whileElementsMounted: autoUpdate,
43
+ // middleware: [
44
+ // offset(5),
45
+ // flip({
46
+ // fallbackAxisSideDirection: "start"
47
+ // }),
48
+ // shift()
49
+ // ]
50
+ // })
51
+ //
52
+ // const hover = useHover(context, { move: false })
53
+ // const focus = useFocus(context)
54
+ // const dismiss = useDismiss(context)
55
+ // const role = useRole(context, { role: "tooltip" })
56
+ //
57
+ // const { getReferenceProps, getFloatingProps } = useInteractions([
58
+ // hover,
59
+ // focus,
60
+ // dismiss,
61
+ // role
62
+ // ])
63
+
64
+ return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", {
65
+ // ref={refs.setReference}
66
+ // tabIndex={-1}
67
+ // style={{flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', wordBreak: 'keep-all'}}
65
68
  // style={{flex: 1}}
66
- ,
67
- className: classnames('', {})
68
- }), headerTemplate ? getTemplate(headerTemplate) : t ? t(text) : text), isOpen && (headerTooltip !== false || headerTemplate || headerTooltip || columnGroupText || headerText) && /*#__PURE__*/React.createElement(FloatingPortal, {
69
- root: document.body
70
- }, /*#__PURE__*/React.createElement(TooltipStyle, _extends({
71
- className: "Tooltip",
72
- ref: refs.setFloating,
73
- style: {
74
- ...floatingStyles,
75
- zIndex: 1999
76
- }
77
- }, getFloatingProps()), headerTooltip && typeof headerTooltip === 'function' ? headerTooltip() : t ? t(tooltip) : tooltip)));
69
+ className: classnames('', {}),
70
+ "data-tooltip-id": "tooltip-header",
71
+ "data-tooltip-content": tooltip,
72
+ "data-tooltip-offset": 16
73
+ }, headerTemplate ? getTemplate(headerTemplate) : t ? t(text) : text));
78
74
  };
79
75
  export default HeaderContent;
@@ -44,11 +44,26 @@ const useColumns = config => {
44
44
  rowKey
45
45
  } = config;
46
46
 
47
+ // const mergedColumns = React.useMemo(
48
+ // () => getMergedColumns<RecordType>(rawMergedColumns || []),
49
+ // [rawMergedColumns],
50
+ // );
51
+ //
52
+ // const [filterStates, setFilterStates] = React.useState<FilterState<RecordType>[]>(() =>
53
+ // collectFilterStates(mergedColumns, true),
54
+ // );
55
+
47
56
  // ====================== Selections ======================
48
57
 
49
- const handleSearch = (selectedKeys, confirm) => {
50
- confirm();
51
- };
58
+ // const handleSearch = (
59
+ // selectedKeys: string[],
60
+ // confirm: any,
61
+ // ) => {
62
+ //
63
+ // confirm()
64
+ //
65
+ // }
66
+
52
67
  const getColumnSearchProps = useCallback(column => ({
53
68
  filterDropdown: ({
54
69
  setSelectedKeys,
@@ -95,10 +110,9 @@ const useColumns = config => {
95
110
  }, /*#__PURE__*/React.createElement(Button, {
96
111
  type: "primary",
97
112
  onClick: () => {
98
- confirm({
99
- closeDropdown: false
100
- });
101
- handleSearch(selectedKeys, confirm);
113
+ // confirm({closeDropdown: false})
114
+ confirm();
115
+ // handleSearch(selectedKeys as string[], confirm)
102
116
  },
103
117
  icon: /*#__PURE__*/React.createElement(SearchOutlined, null),
104
118
  size: "small",
@@ -189,7 +203,7 @@ const useColumns = config => {
189
203
  }
190
204
  };
191
205
  }
192
- if (col.key === 'command') {
206
+ if (col.field === 'command') {
193
207
  return {
194
208
  ...transformedColumn,
195
209
  onCell: () => ({
@@ -72,3 +72,11 @@ export declare const isEditable: <RecordType>(column: ColumnTable, rowData: Reco
72
72
  export declare const isArraysEqual: (arr1: any[], arr2: any[]) => boolean;
73
73
  export declare const editAbleColumns: <T>(columns: ColumnsTable<T>) => ColumnTable<T>[];
74
74
  export declare const findItemPath: (tree: any[], targetItem: any, rowKey: any) => any;
75
+ export declare const filterDataByColumns: (data: any[], queries: any) => any[];
76
+ export declare const filterDataByColumns2: (data: any[], queries: any) => any[];
77
+ export declare const removeFieldRecursive: (data: any[], field: string) => any[];
78
+ export declare const filterDataByColumns3: (data: any[], queries: any[]) => any[];
79
+ export declare function isDateString(str: any): boolean;
80
+ export declare function compareDates(date1: any, date2: any): boolean;
81
+ export declare function compareDate(itemValue: any, value: any): boolean;
82
+ export declare function invalidDate(date: any): boolean;
@@ -808,4 +808,260 @@ export const findItemPath = (tree, targetItem, rowKey) => {
808
808
  }
809
809
  dfs(tree);
810
810
  return result;
811
- };
811
+ };
812
+ export const filterDataByColumns = (data, queries) => {
813
+ if (!queries || queries.length === 0) {
814
+ return data;
815
+ }
816
+ return data.filter(item => {
817
+ let result = null;
818
+ for (const query of queries) {
819
+ const {
820
+ field,
821
+ value,
822
+ operator,
823
+ predicate
824
+ } = query;
825
+ const itemValue = item[field];
826
+ let condition = false;
827
+
828
+ // Normalize string values for comparison
829
+ const itemStr = itemValue?.toString().toLowerCase?.();
830
+ const queryStr = value?.toString().toLowerCase?.();
831
+ switch (operator.toLowerCase()) {
832
+ case "equal":
833
+ if (isDateString(value)) {
834
+ condition = compareDate(itemValue, value);
835
+ } else {
836
+ condition = itemValue == value;
837
+ }
838
+ break;
839
+ case "notequal":
840
+ if (isDateString(value)) {
841
+ condition = !compareDate(itemValue, value);
842
+ } else {
843
+ condition = itemValue != value;
844
+ }
845
+ break;
846
+ case "greaterthan":
847
+ condition = itemValue > value;
848
+ break;
849
+ case "greaterthanorequal":
850
+ condition = itemValue >= value;
851
+ break;
852
+ case "lessthan":
853
+ condition = itemValue < value;
854
+ break;
855
+ case "lessthanorequal":
856
+ condition = itemValue <= value;
857
+ break;
858
+ case "contains":
859
+ condition = itemStr?.includes(queryStr);
860
+ break;
861
+ case "startswith":
862
+ condition = itemStr?.startsWith(queryStr);
863
+ break;
864
+ case "endswith":
865
+ condition = itemStr?.endsWith(queryStr);
866
+ break;
867
+ default:
868
+ console.warn(`Unknown operator: ${operator}`);
869
+ break;
870
+ }
871
+ if (predicate === "and") {
872
+ result = result === null ? condition : result && condition;
873
+ } else if (predicate === "or") {
874
+ result = result === null ? condition : result || condition;
875
+ }
876
+ }
877
+ return result;
878
+ });
879
+ };
880
+ export const filterDataByColumns2 = (data, queries) => {
881
+ if (!queries || queries.length === 0) {
882
+ return data;
883
+ }
884
+ return data.filter(item => {
885
+ // Nếu isFilterState = true thì giữ lại dòng này, không cần kiểm tra filter
886
+ if (item.isFilterState) {
887
+ return true;
888
+ }
889
+ let result = null;
890
+ for (const query of queries) {
891
+ const {
892
+ field,
893
+ value,
894
+ operator,
895
+ predicate
896
+ } = query;
897
+ const itemValue = item[field];
898
+ let condition = false;
899
+
900
+ // Normalize string values for comparison
901
+ const itemStr = itemValue?.toString().toLowerCase?.();
902
+ const queryStr = value?.toString().toLowerCase?.();
903
+ switch (operator.toLowerCase()) {
904
+ case "equal":
905
+ condition = isDateString(value) ? compareDate(itemValue, value) : itemValue == value;
906
+ break;
907
+ case "notequal":
908
+ condition = isDateString(value) ? !compareDate(itemValue, value) : itemValue != value;
909
+ break;
910
+ case "greaterthan":
911
+ condition = itemValue > value;
912
+ break;
913
+ case "greaterthanorequal":
914
+ condition = itemValue >= value;
915
+ break;
916
+ case "lessthan":
917
+ condition = itemValue < value;
918
+ break;
919
+ case "lessthanorequal":
920
+ condition = itemValue <= value;
921
+ break;
922
+ case "contains":
923
+ condition = itemStr?.includes(queryStr);
924
+ break;
925
+ case "startswith":
926
+ condition = itemStr?.startsWith(queryStr);
927
+ break;
928
+ case "endswith":
929
+ condition = itemStr?.endsWith(queryStr);
930
+ break;
931
+ default:
932
+ console.warn(`Unknown operator: ${operator}`);
933
+ break;
934
+ }
935
+
936
+ // Áp dụng toán tử logic (and/or)
937
+ if (predicate === "and") {
938
+ result = result === null ? condition : result && condition;
939
+ } else if (predicate === "or") {
940
+ result = result === null ? condition : result || condition;
941
+ }
942
+ }
943
+ return result;
944
+ });
945
+ };
946
+ export const removeFieldRecursive = (data, field) => {
947
+ return data.map(item => {
948
+ const {
949
+ [field]: _,
950
+ ...rest
951
+ } = item;
952
+ if (rest.children && Array.isArray(rest.children)) {
953
+ rest.children = removeFieldRecursive(rest.children, field);
954
+ }
955
+ return rest;
956
+ });
957
+ };
958
+ export const filterDataByColumns3 = (data, queries) => {
959
+ if (!queries || queries.length === 0) {
960
+ return data;
961
+ }
962
+ return data.filter(item => {
963
+ if (item.isFilterState === true) {
964
+ return true;
965
+ }
966
+ let result = null;
967
+ for (const query of queries) {
968
+ const {
969
+ field,
970
+ value,
971
+ operator,
972
+ predicate
973
+ } = query;
974
+ const itemValue = item[field];
975
+ let condition = false;
976
+ const isDateComparison = isDate(itemValue) || isDateString(value);
977
+ const itemDate = isDateComparison ? new Date(itemValue) : null;
978
+ const queryDate = isDateComparison ? parseToDate(value) : null;
979
+ const itemStr = itemValue?.toString().toLowerCase?.();
980
+ const queryStr = value?.toString().toLowerCase?.();
981
+ switch (operator.toLowerCase()) {
982
+ case "equal":
983
+ condition = isDateComparison ? compareDates(itemDate, queryDate) : itemValue == value;
984
+ break;
985
+ case "notequal":
986
+ condition = isDateComparison ? !compareDates(itemDate, queryDate) : itemValue != value;
987
+ break;
988
+ case "greaterthan":
989
+ // @ts-ignore
990
+ condition = isDateComparison ? itemDate > queryDate : itemValue > value;
991
+
992
+ // condition = isDateComparison ? invalidDate(itemDate) && invalidDate(queryDate) && itemDate > queryDate : itemValue > value;
993
+ break;
994
+ case "greaterthanorequal":
995
+ // @ts-ignore
996
+ condition = isDateComparison ? itemDate >= queryDate : itemValue >= value;
997
+ break;
998
+ case "lessthan":
999
+ // @ts-ignore
1000
+ condition = isDateComparison ? itemDate < queryDate : itemValue < value;
1001
+ break;
1002
+ case "lessthanorequal":
1003
+ // @ts-ignore
1004
+ condition = isDateComparison ? itemDate <= queryDate : itemValue <= value;
1005
+ break;
1006
+ case "contains":
1007
+ condition = itemStr?.includes(queryStr);
1008
+ break;
1009
+ case "startswith":
1010
+ condition = itemStr?.startsWith(queryStr);
1011
+ break;
1012
+ case "endswith":
1013
+ condition = itemStr?.endsWith(queryStr);
1014
+ break;
1015
+ default:
1016
+ console.warn(`Unknown operator: ${operator}`);
1017
+ break;
1018
+ }
1019
+ if (predicate === "and") {
1020
+ result = result === null ? condition : result && condition;
1021
+ } else if (predicate === "or") {
1022
+ result = result === null ? condition : result || condition;
1023
+ }
1024
+ }
1025
+ return result;
1026
+ });
1027
+ };
1028
+
1029
+ // ======= Helper functions ========
1030
+
1031
+ // Kiểm tra có phải Date object không
1032
+ function isDate(value) {
1033
+ return value instanceof Date || !isNaN(Date.parse(value));
1034
+ }
1035
+
1036
+ // Chuỗi MM/YYYY → Date
1037
+ export function isDateString(str) {
1038
+ return typeof str === "string" && (/^\d{2}\/\d{4}$/.test(str) || /^\d{4}-\d{2}-\d{2}$/.test(str));
1039
+ }
1040
+
1041
+ // // Helper: check if a string is in MM/YYYY format
1042
+ // export function isDateString(str: any) {
1043
+ // return typeof str === "string" && /^\d{2}\/\d{4}$/.test(str);
1044
+ // }
1045
+
1046
+ function parseToDate(str) {
1047
+ if (/^\d{2}\/\d{4}$/.test(str)) {
1048
+ const [month, year] = str.split('/');
1049
+ return new Date(parseInt(year), parseInt(month) - 1, 1);
1050
+ }
1051
+ return new Date(str);
1052
+ }
1053
+
1054
+ // So sánh ngày (cùng ngày/tháng/năm)
1055
+ export function compareDates(date1, date2) {
1056
+ return date1.getDate() === date2.getDate() && date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear();
1057
+ }
1058
+
1059
+ // Helper: compare MM/YYYY date string with itemValue
1060
+ export function compareDate(itemValue, value) {
1061
+ const [month, year] = value.split('/').map(Number);
1062
+ const date = new Date(itemValue);
1063
+ return date.getMonth() + 1 === month && date.getFullYear() === year;
1064
+ }
1065
+ export function invalidDate(date) {
1066
+ return date instanceof Date && !isNaN(date.getTime());
1067
+ }
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ type Props = {
3
+ t?: any;
4
+ format?: any;
5
+ min: number | string | undefined;
6
+ max: number | string | undefined;
7
+ onChange?: (values: any[]) => void;
8
+ };
9
+ declare const NumberRange: (props: Props) => React.JSX.Element;
10
+ export default NumberRange;
@@ -0,0 +1,59 @@
1
+ import React, { Fragment } from "react";
2
+ import { NumericFormat } from "react-numeric-component";
3
+ import { Input } from "rc-master-ui";
4
+ const NumberRange = props => {
5
+ const {
6
+ t,
7
+ max,
8
+ min,
9
+ onChange
10
+ } = props;
11
+ const values = React.useMemo(() => [min, max], [min, max]);
12
+
13
+ // const [values, setValues] = React.useState<any[]>(() =>
14
+ // mergedValues,
15
+ // );
16
+
17
+ return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", {
18
+ className: '',
19
+ style: {
20
+ display: 'flex'
21
+ }
22
+ }, /*#__PURE__*/React.createElement("div", {
23
+ style: {
24
+ marginBottom: 8
25
+ }
26
+ }, /*#__PURE__*/React.createElement(NumericFormat, {
27
+ value: values[0] ?? ''
28
+ // value={min}
29
+ // thousandSeparator={checkThousandSeparator(thousandSeparator, decimalSeparator)}
30
+ // decimalSeparator={checkDecimalSeparator(thousandSeparator, decimalSeparator)}
31
+ ,
32
+ allowNegative: true,
33
+ customInput: Input,
34
+ className: ' rounded-0 input-element form-control',
35
+ onValueChange: vals => {
36
+ // onChangeValueFilter(type, values.floatValue, 'min')
37
+
38
+ // setValues([vals.floatValue, values[1]])
39
+ onChange?.([vals.floatValue, max]);
40
+ },
41
+ placeholder: t ? t('Min') : 'Min',
42
+ autoFocus: true
43
+ })), /*#__PURE__*/React.createElement("span", null, "-"), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(NumericFormat, {
44
+ value: values[1] ?? ''
45
+ // value={max}
46
+ // thousandSeparator={checkThousandSeparator(thousandSeparator, decimalSeparator)}
47
+ // decimalSeparator={checkDecimalSeparator(thousandSeparator, decimalSeparator)}
48
+ ,
49
+ allowNegative: true,
50
+ customInput: Input,
51
+ className: ' rounded-0 input-element form-control',
52
+ onValueChange: vals => {
53
+ // setValues([values[0], vals.floatValue])
54
+ onChange?.([min, vals.floatValue]);
55
+ },
56
+ placeholder: t ? t('Max') : 'Max'
57
+ }))));
58
+ };
59
+ export default NumberRange;
@@ -3,11 +3,14 @@ import type { ColumnsTable, GridTableProps } from "../type";
3
3
  import type { GetRowKey } from "../type";
4
4
  type Props<T> = GridTableProps<T> & {
5
5
  tableRef: any;
6
+ triggerFilter?: (queries: any) => void;
6
7
  triggerChangeColumns?: (columns: ColumnsTable<T>, type: string) => void;
7
8
  triggerChangeData?: (newData: T[], type: string) => void;
8
9
  getRowKey: GetRowKey<T>;
9
10
  triggerGroupColumns?: (groupedColumns: string[]) => void;
10
11
  triggerPaste?: (pastedRows: T[], pastedColumnsArray: string[], newData: T[]) => void;
12
+ isFilter?: boolean;
13
+ setIsFilter?: React.Dispatch<React.SetStateAction<boolean>>;
11
14
  };
12
15
  declare const Grid: <RecordType extends object>(props: Props<RecordType>) => React.JSX.Element;
13
16
  export default Grid;