qantler-flaz-dataview 1.0.0

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 (43) hide show
  1. package/package.json +11 -0
  2. package/src/FlazDataView.css +4423 -0
  3. package/src/FlazDataView.jsx +2943 -0
  4. package/src/FlazDataViewList.jsx +787 -0
  5. package/src/MdtActiveFilterBar.jsx +263 -0
  6. package/src/MdtBulkSelectionBar.jsx +91 -0
  7. package/src/MdtColumnPickerPopup.jsx +59 -0
  8. package/src/MdtColumnVisibilityList.jsx +38 -0
  9. package/src/MdtCreateViewModal.jsx +280 -0
  10. package/src/MdtDatetimeValueEditor.jsx +259 -0
  11. package/src/MdtDeleteViewConfirmModal.jsx +83 -0
  12. package/src/MdtDisplayPopup.jsx +170 -0
  13. package/src/MdtEmptyState.jsx +20 -0
  14. package/src/MdtFilterColumnPicker.jsx +66 -0
  15. package/src/MdtFilterOperatorDropdown.jsx +58 -0
  16. package/src/MdtFilterSection.jsx +73 -0
  17. package/src/MdtFilterToolbar.jsx +81 -0
  18. package/src/MdtInlineField.css +221 -0
  19. package/src/MdtInlineField.jsx +187 -0
  20. package/src/MdtInlineFieldRow.jsx +71 -0
  21. package/src/MdtNoDataIllustration.jsx +64 -0
  22. package/src/MdtPopupChecklist.jsx +70 -0
  23. package/src/MdtRowActionsMenu.jsx +281 -0
  24. package/src/MdtSidebarNav.jsx +26 -0
  25. package/src/MdtTabsRow.jsx +354 -0
  26. package/src/MdtTabsSection.jsx +35 -0
  27. package/src/MdtTruncateWithTooltip.jsx +82 -0
  28. package/src/MdtValueEditorPopup.jsx +950 -0
  29. package/src/filterDisplayUtils.jsx +96 -0
  30. package/src/mdtClientSideFilter.js +68 -0
  31. package/src/mdtColumnEditUtils.js +403 -0
  32. package/src/mdtDateFilterUtils.js +135 -0
  33. package/src/mdtExportUtils.js +234 -0
  34. package/src/mdtFilterUtils.js +56 -0
  35. package/src/mdtInlineFieldDisplay.js +66 -0
  36. package/src/mdtMobilePopupPosition.js +107 -0
  37. package/src/mdtMultiSelectDisplay.jsx +279 -0
  38. package/src/mdtSavedViewFilterMatch.js +154 -0
  39. package/src/mdtTabChangeUtils.js +12 -0
  40. package/src/mdtTabStatusRules.js +111 -0
  41. package/src/mdtTableConstants.js +2 -0
  42. package/src/mdtTooltipFormat.js +44 -0
  43. package/src/renderInlineFieldValue.jsx +183 -0
@@ -0,0 +1,263 @@
1
+ import React, { useState } from "react";
2
+ import { ListFilterPlus, X } from "lucide-react";
3
+ import { renderColumnIcon, resolveFilterColumnIcon } from "../../ui/tableColumnIcons";
4
+ import MdtValueEditorPopup from "./MdtValueEditorPopup";
5
+ import MdtFilterColumnPicker from "./MdtFilterColumnPicker";
6
+ import MdtFilterOperatorDropdown from "./MdtFilterOperatorDropdown";
7
+ import { renderFilterChipDisplayValue } from "./filterDisplayUtils";
8
+ import { EDIT_MODE, getColumnFieldVariant } from "./mdtColumnEditUtils";
9
+ import { resolveFilterConfig, getAvailableFilterColumns } from "./mdtFilterUtils";
10
+ import {
11
+ DEFAULT_DATE_FILTER_OPERATOR,
12
+ getDateFilterOperatorLabel,
13
+ isDateLikeFilterColumn,
14
+ } from "./mdtDateFilterUtils";
15
+
16
+ /**
17
+ * Active filter chips bar — reusable in table page and Create View modal.
18
+ */
19
+ const MdtActiveFilterBar = ({
20
+ filterConfig: filterConfigProp,
21
+ /** Prefer filterableColumns; visibleColumns kept for backward compatibility. */
22
+ filterableColumns: filterableColumnsProp,
23
+ visibleColumns,
24
+ activeFilters,
25
+ replacingFilterId,
26
+ setReplacingFilterId,
27
+ replaceSearch,
28
+ setReplaceSearch,
29
+ valueEditId,
30
+ setValueEditId,
31
+ showInnerFilterDropdown,
32
+ setShowInnerFilterDropdown,
33
+ innerFilterSearch,
34
+ setInnerFilterSearch,
35
+ chipReplaceRef,
36
+ chipValueRef,
37
+ innerFilterRef,
38
+ onRemoveFilter,
39
+ onClearAll,
40
+ onAddFilter,
41
+ onUpdateFilterValue,
42
+ onUpdateFilterOperator,
43
+ onReplaceFilterKey,
44
+ onCloseOtherPopups,
45
+ onCloseColumnSortPopup,
46
+ showSaveAs: showSaveAsProp,
47
+ hasAnyFilterValue = false,
48
+ onSaveAs,
49
+ className = "",
50
+ }) => {
51
+ const config = resolveFilterConfig(filterConfigProp);
52
+ const columns = filterableColumnsProp ?? visibleColumns ?? [];
53
+ const showSaveAs = showSaveAsProp ?? config.showSaveAs;
54
+
55
+ const replaceColumns = getAvailableFilterColumns(
56
+ columns,
57
+ activeFilters.filter((f) => f.id !== replacingFilterId),
58
+ replaceSearch,
59
+ );
60
+
61
+ const addColumns = getAvailableFilterColumns(columns, activeFilters, innerFilterSearch);
62
+ const [operatorEditId, setOperatorEditId] = useState(null);
63
+
64
+ return (
65
+ <div className={`mdt-filter-inner${className ? ` ${className}` : ""}`.trim()}>
66
+ <div className="mdt-filter-left">
67
+ {activeFilters.map((filter) => {
68
+ const col = columns.find((c) => c.accessorKey === filter.key);
69
+ const isDateFilter = isDateLikeFilterColumn(col);
70
+ const filterOperator =
71
+ filter.operator ?? DEFAULT_DATE_FILTER_OPERATOR;
72
+
73
+ return (
74
+ <div
75
+ className="mdt-filter-chip"
76
+ key={filter.id}
77
+ style={{ position: "relative" }}
78
+ ref={replacingFilterId === filter.id ? chipReplaceRef : null}
79
+ >
80
+ {config.showChipFieldReplace && (
81
+ <button
82
+ type="button"
83
+ className="mdt-chip-label mdt-chip-label-btn"
84
+ onClick={() => {
85
+ setReplacingFilterId(replacingFilterId === filter.id ? null : filter.id);
86
+ setReplaceSearch("");
87
+ onCloseOtherPopups?.();
88
+ }}
89
+ >
90
+ <span className="mdt-chip-icon">
91
+ {renderColumnIcon(resolveFilterColumnIcon(filter, columns), {
92
+ className: "mdt-chip-svg",
93
+ })}
94
+ </span>
95
+ <span className="mdt-chip-label-text">{filter.label}</span>
96
+ </button>
97
+ )}
98
+
99
+ {config.showChipFieldReplace && replacingFilterId === filter.id && (
100
+ <MdtFilterColumnPicker
101
+ columns={replaceColumns}
102
+ search={replaceSearch}
103
+ onSearchChange={setReplaceSearch}
104
+ onSelectColumn={(col) => {
105
+ onReplaceFilterKey(filter.id, col);
106
+ setReplacingFilterId(null);
107
+ setReplaceSearch("");
108
+ setValueEditId(filter.id);
109
+ }}
110
+ searchPlaceholder={config.searchPlaceholder}
111
+ emptyMessage={config.emptyColumnsMessage}
112
+ dropdownClassName="mdt-filter-dropdown mdt-fd-left mdt-chip-replace-dropdown"
113
+ align="left"
114
+ />
115
+ )}
116
+
117
+ {isDateFilter ? (
118
+ <div
119
+ className="mdt-chip-op-wrap"
120
+ style={{ position: "relative" }}
121
+ >
122
+ <button
123
+ type="button"
124
+ className="mdt-chip-op mdt-chip-op-btn"
125
+ onMouseDown={(e) => e.stopPropagation()}
126
+ onClick={(e) => {
127
+ e.stopPropagation();
128
+ const opening = operatorEditId !== filter.id;
129
+ setOperatorEditId(opening ? filter.id : null);
130
+ setReplacingFilterId(null);
131
+ onCloseOtherPopups?.();
132
+ if (opening) setValueEditId(null);
133
+ }}
134
+ >
135
+ {getDateFilterOperatorLabel(filterOperator)}
136
+ </button>
137
+ {operatorEditId === filter.id && (
138
+ <MdtFilterOperatorDropdown
139
+ operator={filterOperator}
140
+ onSelect={(op) => {
141
+ onUpdateFilterOperator?.(filter.id, op);
142
+ setOperatorEditId(null);
143
+ setValueEditId(filter.id);
144
+ }}
145
+ onClose={() => setOperatorEditId(null)}
146
+ />
147
+ )}
148
+ </div>
149
+ ) : (
150
+ <div className="mdt-chip-op">{config.operatorLabel}</div>
151
+ )}
152
+
153
+ <div
154
+ className="mdt-chip-value-wrap"
155
+ ref={
156
+ valueEditId === filter.id && operatorEditId !== filter.id
157
+ ? chipValueRef
158
+ : null
159
+ }
160
+ style={{ position: "relative" }}
161
+ >
162
+ <button
163
+ type="button"
164
+ className="mdt-chip-value"
165
+ onMouseDown={(e) => e.stopPropagation()}
166
+ onClick={(e) => {
167
+ e.stopPropagation();
168
+ const isOpening = valueEditId !== filter.id;
169
+ setValueEditId(isOpening ? filter.id : null);
170
+ setReplacingFilterId(null);
171
+ onCloseOtherPopups?.();
172
+ }}
173
+ >
174
+ {renderFilterChipDisplayValue(
175
+ filter,
176
+ columns.find((c) => c.accessorKey === filter.key),
177
+ )}
178
+ </button>
179
+
180
+ {valueEditId === filter.id && operatorEditId !== filter.id && col && (
181
+ <MdtValueEditorPopup
182
+ column={col}
183
+ mode={EDIT_MODE.FILTER}
184
+ value={filter.value}
185
+ filterOperator={isDateFilter ? filterOperator : undefined}
186
+ onApply={(v) => {
187
+ onUpdateFilterValue(filter.id, v);
188
+ const variant =
189
+ getColumnFieldVariant(col, EDIT_MODE.FILTER) || "text";
190
+ const isMulti =
191
+ variant === "select" && col?.filterMulti !== false;
192
+ if (variant !== "select" || !isMulti) {
193
+ setValueEditId(null);
194
+ }
195
+ }}
196
+ onCancel={() => setValueEditId(null)}
197
+ />
198
+ )}
199
+ </div>
200
+
201
+ {config.showChipRemove && (
202
+ <button
203
+ type="button"
204
+ className="mdt-chip-remove"
205
+ onClick={() => onRemoveFilter(filter.id)}
206
+ >
207
+ <X size={14} />
208
+ </button>
209
+ )}
210
+ </div>
211
+ );
212
+ })}
213
+
214
+ {config.showAddFilter && (
215
+ <div className="mdt-filter-button-wrap" ref={innerFilterRef}>
216
+ <button
217
+ type="button"
218
+ className="mdt-add-filter"
219
+ onClick={() => {
220
+ onCloseColumnSortPopup?.();
221
+ setShowInnerFilterDropdown((v) => !v);
222
+ }}
223
+ >
224
+ <ListFilterPlus size={16} />
225
+ </button>
226
+
227
+ {showInnerFilterDropdown && (
228
+ <MdtFilterColumnPicker
229
+ columns={addColumns}
230
+ search={innerFilterSearch}
231
+ onSearchChange={setInnerFilterSearch}
232
+ onSelectColumn={(col) => {
233
+ onAddFilter(col);
234
+ setShowInnerFilterDropdown(false);
235
+ setInnerFilterSearch("");
236
+ }}
237
+ searchPlaceholder={config.searchPlaceholder}
238
+ emptyMessage={config.emptyMoreMessage}
239
+ dropdownClassName="mdt-filter-dropdown mdt-fd-left"
240
+ align="left"
241
+ />
242
+ )}
243
+ </div>
244
+ )}
245
+ </div>
246
+
247
+ <div className="mdt-filter-right">
248
+ {config.showClearAll && (
249
+ <button type="button" className="mdt-clear-all" onClick={onClearAll}>
250
+ {config.clearAllLabel}
251
+ </button>
252
+ )}
253
+ {showSaveAs && hasAnyFilterValue && (
254
+ <button type="button" className="mdt-clear-all" onClick={onSaveAs}>
255
+ {config.saveAsLabel}
256
+ </button>
257
+ )}
258
+ </div>
259
+ </div>
260
+ );
261
+ };
262
+
263
+ export default MdtActiveFilterBar;
@@ -0,0 +1,91 @@
1
+ import React from "react";
2
+ import { Trash2 } from "lucide-react";
3
+ import { renderColumnIcon } from "../../ui/tableColumnIcons";
4
+
5
+ /**
6
+ * Bottom bulk action bar — shown when one or more rows are selected.
7
+ * bulkFields: [{ id, label, Icon?, iconName?, column? }]
8
+ */
9
+ const MdtBulkSelectionBar = ({
10
+ selectedCount,
11
+ onClearSelection,
12
+ bulkFields = [],
13
+ onBulkFieldClick,
14
+ onBulkDelete,
15
+ bulkDeleteDisabled = false,
16
+ bulkDeleteDisabledReason = "None of the selected items can be deleted.",
17
+ rightAction = null,
18
+ }) => {
19
+ if (!selectedCount) return null;
20
+
21
+ return (
22
+ <div className="mdt-bulk-bar" role="toolbar" aria-label="Bulk actions">
23
+ <div className="mdt-bulk-bar-inner">
24
+ <div className="mdt-bulk-bar-status">
25
+ <button
26
+ type="button"
27
+ className="mdt-bulk-bar-clear"
28
+ aria-label="Clear selection"
29
+ onClick={onClearSelection}
30
+ />
31
+ <span className="mdt-bulk-bar-count">
32
+ {selectedCount} selected
33
+ </span>
34
+ </div>
35
+
36
+ <div className="mdt-bulk-bar-divider" aria-hidden />
37
+
38
+ <div className="mdt-bulk-bar-actions">
39
+ {onBulkDelete && (
40
+ <div className="mdt-bulk-bar-icons">
41
+ <button
42
+ type="button"
43
+ className={[
44
+ "mdt-bulk-bar-icon-btn",
45
+ bulkDeleteDisabled ? "mdt-bulk-bar-icon-btn--disabled" : "",
46
+ ]
47
+ .filter(Boolean)
48
+ .join(" ")}
49
+ aria-label="Delete"
50
+ title={bulkDeleteDisabled ? bulkDeleteDisabledReason : "Delete"}
51
+ disabled={bulkDeleteDisabled}
52
+ onClick={bulkDeleteDisabled ? undefined : onBulkDelete}
53
+ >
54
+ <Trash2 size={16} />
55
+ </button>
56
+ </div>
57
+ )}
58
+
59
+ {bulkFields.length > 0 && (
60
+ <div className="mdt-bulk-bar-fields">
61
+ {bulkFields.map((field) => {
62
+ const iconEl = renderColumnIcon(field.icon ?? field.iconName, {
63
+ className: "mdt-bulk-field-icon",
64
+ size: 14,
65
+ });
66
+
67
+ return (
68
+ <button
69
+ key={field.id}
70
+ type="button"
71
+ className="mdt-bulk-field-btn"
72
+ onClick={(e) => onBulkFieldClick?.(field.id, field, e)}
73
+ >
74
+ {iconEl}
75
+ <span>{field.label}</span>
76
+ </button>
77
+ );
78
+ })}
79
+ </div>
80
+ )}
81
+ </div>
82
+
83
+ {rightAction && (
84
+ <div className="mdt-bulk-bar-right">{rightAction}</div>
85
+ )}
86
+ </div>
87
+ </div>
88
+ );
89
+ };
90
+
91
+ export default MdtBulkSelectionBar;
@@ -0,0 +1,59 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { createPortal } from "react-dom";
3
+ import MdtColumnVisibilityList from "./MdtColumnVisibilityList";
4
+
5
+ const MdtColumnPickerPopup = ({
6
+ isOpen,
7
+ position,
8
+ columns,
9
+ hiddenColumns,
10
+ onToggleColumn,
11
+ onClose,
12
+ }) => {
13
+ const [search, setSearch] = useState("");
14
+
15
+ useEffect(() => {
16
+ if (!isOpen) {
17
+ setSearch("");
18
+ return undefined;
19
+ }
20
+ const handleOutside = (e) => {
21
+ if (
22
+ !e.target.closest(".mdt-column-picker-popup") &&
23
+ !e.target.closest(".mdt-th-column-picker-btn")
24
+ ) {
25
+ onClose();
26
+ }
27
+ };
28
+ document.addEventListener("mousedown", handleOutside);
29
+ return () => document.removeEventListener("mousedown", handleOutside);
30
+ }, [isOpen, onClose]);
31
+
32
+ if (!isOpen || !position) return null;
33
+
34
+ return createPortal(
35
+ <div
36
+ className="mdt-column-picker-popup mdt-column-picker-popup--portal"
37
+ style={{
38
+ position: "fixed",
39
+ top: position.top,
40
+ left: position.left,
41
+ zIndex: 300000,
42
+ }}
43
+ onMouseDown={(e) => e.stopPropagation()}
44
+ onClick={(e) => e.stopPropagation()}
45
+ >
46
+ <MdtColumnVisibilityList
47
+ columns={columns}
48
+ hiddenColumns={hiddenColumns}
49
+ onToggleColumn={onToggleColumn}
50
+ search={search}
51
+ onSearchChange={setSearch}
52
+ showSearch
53
+ />
54
+ </div>,
55
+ document.body,
56
+ );
57
+ };
58
+
59
+ export default MdtColumnPickerPopup;
@@ -0,0 +1,38 @@
1
+ import React, { useMemo } from "react";
2
+ import MdtPopupChecklist from "./MdtPopupChecklist";
3
+
4
+ /**
5
+ * Column visibility checklist — uses shared popup checklist design.
6
+ */
7
+ const MdtColumnVisibilityList = ({
8
+ columns,
9
+ hiddenColumns,
10
+ onToggleColumn,
11
+ search = "",
12
+ onSearchChange,
13
+ showSearch = true,
14
+ }) => {
15
+ const options = useMemo(
16
+ () =>
17
+ columns.map((col) => ({
18
+ key: col.accessorKey,
19
+ label: col.header,
20
+ icon: col.headerIcon || col.rowIcon || "default",
21
+ checked: !hiddenColumns.includes(col.accessorKey),
22
+ })),
23
+ [columns, hiddenColumns],
24
+ );
25
+
26
+ return (
27
+ <MdtPopupChecklist
28
+ options={options}
29
+ onToggle={onToggleColumn}
30
+ search={search}
31
+ onSearchChange={onSearchChange}
32
+ showSearch={showSearch}
33
+ emptyText="No columns found"
34
+ />
35
+ );
36
+ };
37
+
38
+ export default MdtColumnVisibilityList;