@seedgrid/fe-components 2026.3.31 → 2026.4.8-1

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.
@@ -1,6 +1,8 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React from "react";
4
+ import { createPortal } from "react-dom";
5
+ import { Check, GripVertical, SlidersHorizontal } from "lucide-react";
4
6
  import { SgButton } from "../buttons/SgButton";
5
7
  import { SgGroupBox } from "../layout/SgGroupBox";
6
8
  import { t, useComponentsI18n } from "../i18n";
@@ -112,6 +114,28 @@ function rowsAreEqual(rowA, rowB, dataKey) {
112
114
  return rowA === rowB;
113
115
  return getRowIdentity(rowA, dataKey) === getRowIdentity(rowB, dataKey);
114
116
  }
117
+ function getColumnKey(column, index) {
118
+ if (column.columnId?.trim())
119
+ return `columnId:${column.columnId.trim()}`;
120
+ if (column.field?.trim())
121
+ return `field:${column.field.trim()}`;
122
+ return `index:${index}`;
123
+ }
124
+ function moveItem(list, fromIndex, toIndex) {
125
+ if (fromIndex === toIndex)
126
+ return list;
127
+ if (fromIndex < 0 || fromIndex >= list.length)
128
+ return list;
129
+ if (toIndex < 0 || toIndex >= list.length)
130
+ return list;
131
+ const next = [...list];
132
+ const item = next[fromIndex];
133
+ if (item === undefined)
134
+ return list;
135
+ next.splice(fromIndex, 1);
136
+ next.splice(toIndex, 0, item);
137
+ return next;
138
+ }
115
139
  function resolveAlignmentClass(align) {
116
140
  if (align === "center")
117
141
  return "text-center";
@@ -121,7 +145,7 @@ function resolveAlignmentClass(align) {
121
145
  }
122
146
  function SgDatatableBase(props, imperativeRef) {
123
147
  const i18n = useComponentsI18n();
124
- const { id, title, value, columns, dataKey, lazy = false, totalRecords: controlledTotalRecords, paginator = false, rows = 10, first, rowsPerPageOptions, onPage, sortField, sortOrder, onSort, removableSort = true, selectionMode, selection, onSelectionChange, showGlobalFilter = false, globalFilter, globalFilterPlaceholder, onGlobalFilterChange, showColumnFilters = false, filters, onFilter, showClearFiltersButton = false, stripedRows = false, showGridlines = false, hoverableRows = true, loading = false, emptyMessage, className = "", style, tableClassName = "", rowClassName, groupBoxProps = {} } = props;
148
+ const { id, title, value, columns, dataKey, lazy = false, totalRecords: controlledTotalRecords, paginator = false, rows = 10, first, rowsPerPageOptions, onPage, sortField, sortOrder, onSort, removableSort = true, selectionMode, selection, onSelectionChange, showGlobalFilter = false, globalFilter, globalFilterPlaceholder, onGlobalFilterChange, showColumnFilters = false, filters, onFilter, showClearFiltersButton = false, stripedRows = false, showGridlines = false, hoverableRows = true, loading = false, emptyMessage, className = "", style, tableClassName = "", rowClassName, groupBoxProps = {}, showColumnManager = true, columnManagerLabel, columnManagerMaxHeight = 320 } = props;
125
149
  const isFirstControlled = first !== undefined;
126
150
  const isSortFieldControlled = sortField !== undefined;
127
151
  const isSortOrderControlled = sortOrder !== undefined;
@@ -135,6 +159,22 @@ function SgDatatableBase(props, imperativeRef) {
135
159
  const [internalSelection, setInternalSelection] = React.useState(null);
136
160
  const [internalGlobalFilter, setInternalGlobalFilter] = React.useState(globalFilter ?? "");
137
161
  const [internalFilters, setInternalFilters] = React.useState(() => normalizeFilters(filters));
162
+ const columnManagerRef = React.useRef(null);
163
+ const columnManagerButtonRef = React.useRef(null);
164
+ const columnManagerPanelRef = React.useRef(null);
165
+ const [isColumnManagerOpen, setIsColumnManagerOpen] = React.useState(false);
166
+ const [draggingColumnKey, setDraggingColumnKey] = React.useState(null);
167
+ const [columnManagerPosition, setColumnManagerPosition] = React.useState(null);
168
+ const columnDescriptors = React.useMemo(() => columns.map((column, index) => ({
169
+ key: getColumnKey(column, index),
170
+ column,
171
+ originalIndex: index
172
+ })), [columns]);
173
+ const [columnOrder, setColumnOrder] = React.useState(() => columnDescriptors.map((item) => item.key));
174
+ const [hiddenColumnsMap, setHiddenColumnsMap] = React.useState(() => columnDescriptors.reduce((acc, item) => {
175
+ acc[item.key] = Boolean(item.column.hidden);
176
+ return acc;
177
+ }, {}));
138
178
  React.useEffect(() => {
139
179
  if (!isFirstControlled)
140
180
  return;
@@ -168,7 +208,75 @@ function SgDatatableBase(props, imperativeRef) {
168
208
  return;
169
209
  setInternalFilters(normalizeFilters(filters));
170
210
  }, [isFiltersControlled, filters]);
171
- const visibleColumns = React.useMemo(() => columns.filter((column) => !column.hidden), [columns]);
211
+ React.useEffect(() => {
212
+ const availableKeys = columnDescriptors.map((item) => item.key);
213
+ setColumnOrder((prev) => {
214
+ const kept = prev.filter((key) => availableKeys.includes(key));
215
+ const missing = availableKeys.filter((key) => !kept.includes(key));
216
+ return [...kept, ...missing];
217
+ });
218
+ setHiddenColumnsMap((prev) => {
219
+ const next = {};
220
+ for (const item of columnDescriptors) {
221
+ next[item.key] = prev[item.key] ?? Boolean(item.column.hidden);
222
+ }
223
+ return next;
224
+ });
225
+ }, [columnDescriptors]);
226
+ React.useEffect(() => {
227
+ if (!isColumnManagerOpen)
228
+ return;
229
+ const handlePointerDown = (event) => {
230
+ const target = event.target;
231
+ if (columnManagerRef.current?.contains(target))
232
+ return;
233
+ if (columnManagerPanelRef.current?.contains(target))
234
+ return;
235
+ setIsColumnManagerOpen(false);
236
+ };
237
+ document.addEventListener("mousedown", handlePointerDown);
238
+ return () => document.removeEventListener("mousedown", handlePointerDown);
239
+ }, [isColumnManagerOpen]);
240
+ const updateColumnManagerPosition = React.useCallback(() => {
241
+ const button = columnManagerButtonRef.current;
242
+ if (!button)
243
+ return;
244
+ const rect = button.getBoundingClientRect();
245
+ const panelWidth = 300;
246
+ const viewportPadding = 12;
247
+ const left = Math.min(Math.max(rect.left, viewportPadding), Math.max(viewportPadding, window.innerWidth - panelWidth - viewportPadding));
248
+ setColumnManagerPosition({
249
+ top: rect.bottom + 8,
250
+ left
251
+ });
252
+ }, []);
253
+ React.useLayoutEffect(() => {
254
+ if (!isColumnManagerOpen)
255
+ return;
256
+ updateColumnManagerPosition();
257
+ const raf = window.requestAnimationFrame(updateColumnManagerPosition);
258
+ return () => window.cancelAnimationFrame(raf);
259
+ }, [isColumnManagerOpen, updateColumnManagerPosition]);
260
+ React.useEffect(() => {
261
+ if (!isColumnManagerOpen)
262
+ return;
263
+ const handleViewportChange = () => updateColumnManagerPosition();
264
+ const useCapture = true;
265
+ window.addEventListener("resize", handleViewportChange);
266
+ window.addEventListener("scroll", handleViewportChange, useCapture);
267
+ return () => {
268
+ window.removeEventListener("resize", handleViewportChange);
269
+ window.removeEventListener("scroll", handleViewportChange, useCapture);
270
+ };
271
+ }, [isColumnManagerOpen, updateColumnManagerPosition]);
272
+ const orderedColumns = React.useMemo(() => {
273
+ const map = new Map(columnDescriptors.map((item) => [item.key, item]));
274
+ return columnOrder
275
+ .map((key) => map.get(key))
276
+ .filter((item) => Boolean(item));
277
+ }, [columnDescriptors, columnOrder]);
278
+ const visibleColumns = React.useMemo(() => orderedColumns.filter((item) => !hiddenColumnsMap[item.key]).map((item) => item.column), [orderedColumns, hiddenColumnsMap]);
279
+ const visibleColumnCount = React.useMemo(() => orderedColumns.filter((item) => !hiddenColumnsMap[item.key]).length, [orderedColumns, hiddenColumnsMap]);
172
280
  const currentFirst = isFirstControlled ? Math.max(0, first ?? 0) : internalFirst;
173
281
  const currentRows = Math.max(1, internalRows);
174
282
  const currentSortField = isSortFieldControlled ? sortField ?? null : internalSortField;
@@ -379,61 +487,134 @@ function SgDatatableBase(props, imperativeRef) {
379
487
  : [...previous, rowData];
380
488
  commitSelection(next);
381
489
  }, [selectionMode, currentSelection, dataKey, commitSelection]);
490
+ const resolvedColumnManagerLabel = columnManagerLabel ??
491
+ resolveMessage(t(i18n, "components.datatable.columns"), "components.datatable.columns", "Colunas");
492
+ const restoreColumnsLabel = resolveMessage(t(i18n, "components.datatable.restoreColumns"), "components.datatable.restoreColumns", "Restaurar padrão");
493
+ const showAllColumnsLabel = resolveMessage(t(i18n, "components.datatable.showAllColumns"), "components.datatable.showAllColumns", "Mostrar todas");
494
+ const dragHandleLabel = resolveMessage(t(i18n, "components.datatable.dragToReorder"), "components.datatable.dragToReorder", "Arrastar para reordenar");
495
+ const toggleColumnVisibility = React.useCallback((columnKey, forceVisible) => {
496
+ setHiddenColumnsMap((prev) => {
497
+ const isCurrentlyHidden = Boolean(prev[columnKey]);
498
+ const willHide = forceVisible === undefined ? !isCurrentlyHidden : !forceVisible;
499
+ if (willHide && visibleColumnCount <= 1) {
500
+ return prev;
501
+ }
502
+ return {
503
+ ...prev,
504
+ [columnKey]: willHide
505
+ };
506
+ });
507
+ }, [visibleColumnCount]);
508
+ const handleReorderColumn = React.useCallback((fromKey, toKey) => {
509
+ setColumnOrder((prev) => {
510
+ const fromIndex = prev.indexOf(fromKey);
511
+ const toIndex = prev.indexOf(toKey);
512
+ if (fromIndex < 0 || toIndex < 0)
513
+ return prev;
514
+ return moveItem(prev, fromIndex, toIndex);
515
+ });
516
+ }, []);
517
+ const restoreDefaultColumns = React.useCallback(() => {
518
+ setColumnOrder(columnDescriptors.map((item) => item.key));
519
+ setHiddenColumnsMap(columnDescriptors.reduce((acc, item) => {
520
+ acc[item.key] = Boolean(item.column.hidden);
521
+ return acc;
522
+ }, {}));
523
+ }, [columnDescriptors]);
524
+ const showAllColumns = React.useCallback(() => {
525
+ setHiddenColumnsMap((prev) => {
526
+ const next = { ...prev };
527
+ for (const item of columnDescriptors) {
528
+ next[item.key] = false;
529
+ }
530
+ return next;
531
+ });
532
+ }, [columnDescriptors]);
382
533
  const resolvedTitle = (groupBoxProps.title ?? title ?? "").trim() || " ";
383
- return (_jsx("div", { className: className, style: style, children: _jsx(SgGroupBox, { ...groupBoxProps, title: resolvedTitle, children: _jsxs("div", { className: "space-y-3", children: [shouldShowToolbar ? (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [showGlobalFilter ? (_jsx("input", { value: currentGlobalFilter, onChange: (event) => commitFilters(currentFilters, event.target.value), placeholder: globalFilterLabel, className: "min-w-[220px] flex-1 rounded-md border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-input-bg,var(--sg-surface)))] px-3 py-2 text-sm text-[rgb(var(--sg-input-fg,var(--sg-text)))] placeholder:text-[rgb(var(--sg-input-placeholder,var(--sg-muted)))] outline-none focus:ring-2 focus:ring-[rgb(var(--sg-ring))]" })) : null, showClearFiltersButton ? (_jsx(SgButton, { size: "sm", appearance: "outline", onClick: clearFilters, children: clearFiltersLabel })) : null] })) : null, _jsx("div", { className: "relative", children: _jsx("div", { className: "overflow-x-auto rounded-lg border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface))]", children: _jsxs("table", { id: id, className: cn("min-w-full border-collapse text-sm", tableClassName), children: [_jsxs("thead", { children: [_jsx("tr", { className: "bg-[rgb(var(--sg-primary-50))]", children: visibleColumns.map((column, columnIndex) => {
384
- const sortCandidate = column.sortField ?? column.field;
385
- const isSorted = Boolean(sortCandidate) && sortCandidate === currentSortField;
386
- const sortIcon = !column.sortable
387
- ? null
388
- : isSorted
389
- ? currentSortOrder === 1
390
- ? " ^"
391
- : currentSortOrder === -1
392
- ? " v"
393
- : " <>"
394
- : " <>";
395
- return (_jsx("th", { className: cn("px-3 py-2 font-semibold text-[rgb(var(--sg-text))]", resolveAlignmentClass(column.align), showGridlines ? "border-b border-r border-[rgb(var(--sg-border))] last:border-r-0" : "border-b border-[rgb(var(--sg-border))]", column.headerClassName, column.className), style: { width: toCssSize(column.width), minWidth: toCssSize(column.minWidth) }, children: column.sortable ? (_jsxs("button", { type: "button", onClick: () => handleHeaderSort(column), className: cn("inline-flex items-center gap-1 font-semibold", resolveAlignmentClass(column.align), "text-[rgb(var(--sg-text))] hover:text-[rgb(var(--sg-primary-600))]"), children: [_jsx("span", { children: column.header }), _jsx("span", { "aria-hidden": "true", children: sortIcon })] })) : (_jsx("span", { children: column.header })) }, `head-${column.field ?? columnIndex}`));
396
- }) }), shouldShowFiltersRow ? (_jsx("tr", { children: visibleColumns.map((column, columnIndex) => {
397
- const filterField = column.filterField ?? column.field;
398
- const filterValue = filterField ? currentFilters[filterField] ?? "" : "";
399
- return (_jsx("th", { className: cn("px-3 py-2 align-top", showGridlines ? "border-b border-r border-[rgb(var(--sg-border))] last:border-r-0" : "border-b border-[rgb(var(--sg-border))]"), children: column.filter && filterField ? (_jsx("input", { value: filterValue, onChange: (event) => {
400
- const nextFilters = {
401
- ...currentFilters,
402
- [filterField]: event.target.value
403
- };
404
- const normalized = normalizeFilters(nextFilters);
405
- commitFilters(normalized, currentGlobalFilter);
406
- }, placeholder: column.filterPlaceholder ?? t(i18n, "components.datatable.columnFilterPlaceholder", { column: String(column.header ?? "") }), className: "w-full rounded-md border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-input-bg,var(--sg-surface)))] px-2 py-1 text-xs text-[rgb(var(--sg-input-fg,var(--sg-text)))] placeholder:text-[rgb(var(--sg-input-placeholder,var(--sg-muted)))] outline-none focus:ring-2 focus:ring-[rgb(var(--sg-ring))]" })) : null }, `filter-${column.field ?? columnIndex}`));
407
- }) })) : null] }), _jsx("tbody", { children: loading ? (_jsx("tr", { children: _jsx("td", { colSpan: Math.max(1, visibleColumns.length), className: "px-4 py-6 text-center text-sm text-[rgb(var(--sg-muted))]", children: loadingLabel }) })) : pagedRows.length === 0 ? (_jsx("tr", { children: _jsx("td", { colSpan: Math.max(1, visibleColumns.length), className: "px-4 py-6 text-center text-sm text-[rgb(var(--sg-muted))]", children: emptyLabel }) })) : (pagedRows.map((rowData, rowIndex) => {
408
- const absoluteRowIndex = safeFirst + rowIndex;
409
- const selected = isRowSelected(rowData);
410
- const customRowClass = typeof rowClassName === "function" ? rowClassName(rowData, absoluteRowIndex) : rowClassName;
411
- return (_jsx("tr", { "aria-selected": selected || undefined, onClick: (event) => {
412
- const target = event.target;
413
- if (target.closest("button,a,input,select,textarea,label,[data-sg-stop-row-select='true']")) {
414
- return;
415
- }
416
- handleRowSelection(rowData);
417
- }, className: cn(selectionMode ? "cursor-pointer" : "", stripedRows && absoluteRowIndex % 2 === 1 ? "bg-[rgb(var(--sg-primary-50))]" : "", hoverableRows ? "hover:bg-[rgb(var(--sg-primary-100))]" : "", selected ? "bg-[rgb(var(--sg-primary-100))]" : "", customRowClass), children: visibleColumns.map((column, columnIndex) => {
418
- const cellField = column.field;
419
- const cellValue = getFieldValue(rowData, cellField);
420
- const customCellClass = typeof column.bodyClassName === "function"
421
- ? column.bodyClassName(rowData, absoluteRowIndex)
422
- : column.bodyClassName;
423
- const renderedValue = column.body
424
- ? column.body(rowData, {
425
- rowData,
426
- rowIndex: absoluteRowIndex,
427
- field: cellField,
428
- value: cellValue
429
- })
430
- : (_jsx("span", { children: cellValue === null || cellValue === undefined ? "-" : String(cellValue) }));
431
- return (_jsx("td", { className: cn("px-3 py-2 text-[rgb(var(--sg-text))]", resolveAlignmentClass(column.align), showGridlines ? "border-b border-r border-[rgb(var(--sg-border))] last:border-r-0" : "border-b border-[rgb(var(--sg-border))]", column.className, customCellClass), style: { width: toCssSize(column.width), minWidth: toCssSize(column.minWidth) }, children: renderedValue }, `cell-${cellField ?? columnIndex}-${absoluteRowIndex}`));
432
- }) }, String(getRowIdentity(rowData, dataKey) ?? absoluteRowIndex)));
433
- })) }), hasFooter ? (_jsx("tfoot", { children: _jsx("tr", { className: "bg-[rgb(var(--sg-primary-50))]", children: visibleColumns.map((column, columnIndex) => {
434
- const footerValue = typeof column.footer === "function" ? column.footer(sortedRows) : column.footer;
435
- return (_jsx("td", { className: cn("px-3 py-2 font-semibold text-[rgb(var(--sg-text))]", resolveAlignmentClass(column.align), showGridlines ? "border-t border-r border-[rgb(var(--sg-border))] last:border-r-0" : "border-t border-[rgb(var(--sg-border))]", column.className), style: { width: toCssSize(column.width), minWidth: toCssSize(column.minWidth) }, children: footerValue ?? null }, `foot-${column.field ?? columnIndex}`));
436
- }) }) })) : null] }) }) }), paginator ? (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(SgButton, { size: "sm", appearance: "outline", disabled: currentPage <= 1, onClick: () => goToPage(currentPage - 1), children: prevLabel }), pageWindow.map((pageNumber) => (_jsx(SgButton, { size: "sm", appearance: pageNumber === currentPage ? "solid" : "outline", onClick: () => goToPage(pageNumber), children: String(pageNumber) }, `page-${pageNumber}`))), _jsx(SgButton, { size: "sm", appearance: "outline", disabled: currentPage >= pageCount, onClick: () => goToPage(currentPage + 1), children: nextLabel }), _jsx("span", { className: "min-w-[180px] text-xs text-[rgb(var(--sg-muted))] md:ml-auto", children: pageReport }), rowsPerPageOptions && rowsPerPageOptions.length > 0 ? (_jsxs("label", { className: "ml-auto inline-flex items-center gap-2 text-xs text-[rgb(var(--sg-muted))] md:ml-0", children: [_jsx("span", { children: rowsPerPageLabel }), _jsx("select", { value: currentRows, onChange: (event) => {
534
+ return (_jsx("div", { className: className, style: style, children: _jsx(SgGroupBox, { ...groupBoxProps, title: resolvedTitle, children: _jsxs("div", { className: "space-y-3", children: [shouldShowToolbar ? (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [showGlobalFilter ? (_jsx("input", { value: currentGlobalFilter, onChange: (event) => commitFilters(currentFilters, event.target.value), placeholder: globalFilterLabel, className: "min-w-[220px] flex-1 rounded-md border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-input-bg,var(--sg-surface)))] px-3 py-2 text-sm text-[rgb(var(--sg-input-fg,var(--sg-text)))] placeholder:text-[rgb(var(--sg-input-placeholder,var(--sg-muted)))] outline-none focus:ring-2 focus:ring-[rgb(var(--sg-ring))]" })) : null, showClearFiltersButton ? (_jsx(SgButton, { size: "sm", appearance: "outline", onClick: clearFilters, children: clearFiltersLabel })) : null] })) : null, _jsxs("div", { className: "relative", ref: columnManagerRef, children: [showColumnManager ? (_jsx("div", { className: "mb-2 flex items-center justify-start", children: _jsx("button", { ref: columnManagerButtonRef, type: "button", "aria-label": resolvedColumnManagerLabel, title: resolvedColumnManagerLabel, onClick: () => setIsColumnManagerOpen((prev) => !prev), className: "inline-flex h-9 w-9 items-center justify-center rounded-md border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface))] text-[rgb(var(--sg-primary-600))] shadow-sm transition hover:bg-[rgb(var(--sg-primary-50))] hover:text-[rgb(var(--sg-primary-700))]", children: _jsx(SlidersHorizontal, { size: 18 }) }) })) : null, showColumnManager && isColumnManagerOpen && columnManagerPosition && typeof document !== "undefined"
535
+ ? createPortal(_jsxs("div", { ref: columnManagerPanelRef, className: "fixed z-[1400] w-[300px] rounded-xl border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface))] shadow-xl", style: {
536
+ top: columnManagerPosition.top,
537
+ left: columnManagerPosition.left
538
+ }, children: [_jsxs("div", { className: "flex items-center gap-2 border-b border-[rgb(var(--sg-border))] px-4 py-3", children: [_jsx(SlidersHorizontal, { size: 18, className: "text-[rgb(var(--sg-primary-600))]" }), _jsx("span", { className: "text-sm font-semibold text-[rgb(var(--sg-text))]", children: resolvedColumnManagerLabel })] }), _jsx("div", { className: "overflow-y-auto px-2 py-2", style: { maxHeight: toCssSize(columnManagerMaxHeight) }, children: _jsx("div", { className: "space-y-1", children: orderedColumns.map((item) => {
539
+ const isHidden = Boolean(hiddenColumnsMap[item.key]);
540
+ const isHideable = item.column.hideable !== false;
541
+ const isReorderable = item.column.reorderable !== false;
542
+ const canHideThisColumn = isHideable && (!isHidden ? visibleColumnCount > 1 : true);
543
+ const columnLabel = typeof item.column.header === "string" || typeof item.column.header === "number"
544
+ ? String(item.column.header)
545
+ : item.column.field ?? item.key;
546
+ return (_jsxs("div", { draggable: isReorderable, onDragStart: () => setDraggingColumnKey(item.key), onDragOver: (event) => {
547
+ if (!isReorderable)
548
+ return;
549
+ event.preventDefault();
550
+ }, onDrop: (event) => {
551
+ event.preventDefault();
552
+ if (!isReorderable)
553
+ return;
554
+ if (!draggingColumnKey || draggingColumnKey === item.key)
555
+ return;
556
+ handleReorderColumn(draggingColumnKey, item.key);
557
+ setDraggingColumnKey(null);
558
+ }, onDragEnd: () => setDraggingColumnKey(null), className: cn("flex items-center gap-3 rounded-md px-2 py-2", draggingColumnKey === item.key ? "opacity-60" : "", "hover:bg-[rgb(var(--sg-primary-50))]"), children: [_jsx("button", { type: "button", disabled: !canHideThisColumn, onClick: () => toggleColumnVisibility(item.key), className: cn("inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-md border transition", !isHidden
559
+ ? "border-[rgb(var(--sg-primary-600))] bg-[rgb(var(--sg-primary-600))] text-white"
560
+ : "border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface))] text-transparent", !canHideThisColumn ? "cursor-not-allowed opacity-50" : "hover:scale-[1.02]"), children: _jsx(Check, { size: 14 }) }), _jsx("button", { type: "button", disabled: !canHideThisColumn, onClick: () => toggleColumnVisibility(item.key), className: cn("flex-1 truncate text-left text-sm", isHidden
561
+ ? "text-[rgb(var(--sg-muted))]"
562
+ : "text-[rgb(var(--sg-text))]", !canHideThisColumn ? "cursor-not-allowed" : ""), children: columnLabel }), _jsx("div", { className: cn("inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-[rgb(var(--sg-muted))]", isReorderable ? "cursor-grab active:cursor-grabbing" : "opacity-40"), title: dragHandleLabel, children: _jsx(GripVertical, { size: 16 }) })] }, `manager-${item.key}`));
563
+ }) }) }), _jsxs("div", { className: "flex items-center gap-2 border-t border-[rgb(var(--sg-border))] px-3 py-3", children: [_jsx(SgButton, { size: "sm", appearance: "outline", onClick: restoreDefaultColumns, children: restoreColumnsLabel }), _jsx(SgButton, { size: "sm", appearance: "outline", onClick: showAllColumns, children: showAllColumnsLabel })] })] }), document.body)
564
+ : null, _jsx("div", { className: "overflow-x-auto rounded-lg border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface))]", children: _jsxs("table", { id: id, className: cn("min-w-full border-collapse text-sm", tableClassName), children: [_jsxs("thead", { children: [_jsx("tr", { className: "bg-[rgb(var(--sg-primary-50))]", children: visibleColumns.map((column, columnIndex) => {
565
+ const sortCandidate = column.sortField ?? column.field;
566
+ const isSorted = Boolean(sortCandidate) && sortCandidate === currentSortField;
567
+ const sortIcon = !column.sortable
568
+ ? null
569
+ : isSorted
570
+ ? currentSortOrder === 1
571
+ ? " ^"
572
+ : currentSortOrder === -1
573
+ ? " v"
574
+ : " <>"
575
+ : " <>";
576
+ return (_jsx("th", { className: cn("px-3 py-2 font-semibold text-[rgb(var(--sg-text))]", resolveAlignmentClass(column.align), showGridlines ? "border-b border-r border-[rgb(var(--sg-border))] last:border-r-0" : "border-b border-[rgb(var(--sg-border))]", column.headerClassName, column.className), style: { width: toCssSize(column.width), minWidth: toCssSize(column.minWidth) }, children: column.sortable ? (_jsxs("button", { type: "button", onClick: () => handleHeaderSort(column), className: cn("inline-flex items-center gap-1 font-semibold", resolveAlignmentClass(column.align), "text-[rgb(var(--sg-text))] hover:text-[rgb(var(--sg-primary-600))]"), children: [_jsx("span", { children: column.header }), _jsx("span", { "aria-hidden": "true", children: sortIcon })] })) : (_jsx("span", { children: column.header })) }, `head-${column.columnId ?? column.field ?? columnIndex}`));
577
+ }) }), shouldShowFiltersRow ? (_jsx("tr", { children: visibleColumns.map((column, columnIndex) => {
578
+ const filterField = column.filterField ?? column.field;
579
+ const filterValue = filterField ? currentFilters[filterField] ?? "" : "";
580
+ return (_jsx("th", { className: cn("px-3 py-2 align-top", showGridlines ? "border-b border-r border-[rgb(var(--sg-border))] last:border-r-0" : "border-b border-[rgb(var(--sg-border))]"), children: column.filter && filterField ? (_jsx("input", { value: filterValue, onChange: (event) => {
581
+ const nextFilters = {
582
+ ...currentFilters,
583
+ [filterField]: event.target.value
584
+ };
585
+ const normalized = normalizeFilters(nextFilters);
586
+ commitFilters(normalized, currentGlobalFilter);
587
+ }, placeholder: column.filterPlaceholder ?? t(i18n, "components.datatable.columnFilterPlaceholder", { column: String(column.header ?? "") }), className: "w-full rounded-md border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-input-bg,var(--sg-surface)))] px-2 py-1 text-xs text-[rgb(var(--sg-input-fg,var(--sg-text)))] placeholder:text-[rgb(var(--sg-input-placeholder,var(--sg-muted)))] outline-none focus:ring-2 focus:ring-[rgb(var(--sg-ring))]" })) : null }, `filter-${column.columnId ?? column.field ?? columnIndex}`));
588
+ }) })) : null] }), _jsx("tbody", { children: loading ? (_jsx("tr", { children: _jsx("td", { colSpan: Math.max(1, visibleColumns.length), className: "px-4 py-6 text-center text-sm text-[rgb(var(--sg-muted))]", children: loadingLabel }) })) : pagedRows.length === 0 ? (_jsx("tr", { children: _jsx("td", { colSpan: Math.max(1, visibleColumns.length), className: "px-4 py-6 text-center text-sm text-[rgb(var(--sg-muted))]", children: emptyLabel }) })) : (pagedRows.map((rowData, rowIndex) => {
589
+ const absoluteRowIndex = safeFirst + rowIndex;
590
+ const selected = isRowSelected(rowData);
591
+ const customRowClass = typeof rowClassName === "function" ? rowClassName(rowData, absoluteRowIndex) : rowClassName;
592
+ return (_jsx("tr", { "aria-selected": selected || undefined, onClick: (event) => {
593
+ const target = event.target;
594
+ if (target.closest("button,a,input,select,textarea,label,[data-sg-stop-row-select='true']")) {
595
+ return;
596
+ }
597
+ handleRowSelection(rowData);
598
+ }, className: cn(selectionMode ? "cursor-pointer" : "", stripedRows && absoluteRowIndex % 2 === 1 ? "bg-[rgb(var(--sg-primary-50))]" : "", hoverableRows ? "hover:bg-[rgb(var(--sg-primary-100))]" : "", selected ? "bg-[rgb(var(--sg-primary-100))]" : "", customRowClass), children: visibleColumns.map((column, columnIndex) => {
599
+ const cellField = column.field;
600
+ const cellValue = getFieldValue(rowData, cellField);
601
+ const customCellClass = typeof column.bodyClassName === "function"
602
+ ? column.bodyClassName(rowData, absoluteRowIndex)
603
+ : column.bodyClassName;
604
+ const renderedValue = column.body
605
+ ? column.body(rowData, {
606
+ rowData,
607
+ rowIndex: absoluteRowIndex,
608
+ field: cellField,
609
+ value: cellValue
610
+ })
611
+ : (_jsx("span", { children: cellValue === null || cellValue === undefined ? "-" : String(cellValue) }));
612
+ return (_jsx("td", { className: cn("px-3 py-2 text-[rgb(var(--sg-text))]", resolveAlignmentClass(column.align), showGridlines ? "border-b border-r border-[rgb(var(--sg-border))] last:border-r-0" : "border-b border-[rgb(var(--sg-border))]", column.className, customCellClass), style: { width: toCssSize(column.width), minWidth: toCssSize(column.minWidth) }, children: renderedValue }, `cell-${column.columnId ?? cellField ?? columnIndex}-${absoluteRowIndex}`));
613
+ }) }, String(getRowIdentity(rowData, dataKey) ?? absoluteRowIndex)));
614
+ })) }), hasFooter ? (_jsx("tfoot", { children: _jsx("tr", { className: "bg-[rgb(var(--sg-primary-50))]", children: visibleColumns.map((column, columnIndex) => {
615
+ const footerValue = typeof column.footer === "function" ? column.footer(sortedRows) : column.footer;
616
+ return (_jsx("td", { className: cn("px-3 py-2 font-semibold text-[rgb(var(--sg-text))]", resolveAlignmentClass(column.align), showGridlines ? "border-t border-r border-[rgb(var(--sg-border))] last:border-r-0" : "border-t border-[rgb(var(--sg-border))]", column.className), style: { width: toCssSize(column.width), minWidth: toCssSize(column.minWidth) }, children: footerValue ?? null }, `foot-${column.columnId ?? column.field ?? columnIndex}`));
617
+ }) }) })) : null] }) })] }), paginator ? (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(SgButton, { size: "sm", appearance: "outline", disabled: currentPage <= 1, onClick: () => goToPage(currentPage - 1), children: prevLabel }), pageWindow.map((pageNumber) => (_jsx(SgButton, { size: "sm", appearance: pageNumber === currentPage ? "solid" : "outline", onClick: () => goToPage(pageNumber), children: String(pageNumber) }, `page-${pageNumber}`))), _jsx(SgButton, { size: "sm", appearance: "outline", disabled: currentPage >= pageCount, onClick: () => goToPage(currentPage + 1), children: nextLabel }), _jsx("span", { className: "min-w-[180px] text-xs text-[rgb(var(--sg-muted))] md:ml-auto", children: pageReport }), rowsPerPageOptions && rowsPerPageOptions.length > 0 ? (_jsxs("label", { className: "ml-auto inline-flex items-center gap-2 text-xs text-[rgb(var(--sg-muted))] md:ml-0", children: [_jsx("span", { children: rowsPerPageLabel }), _jsx("select", { value: currentRows, onChange: (event) => {
437
618
  const nextRows = Number(event.target.value) || currentRows;
438
619
  commitPage(0, nextRows);
439
620
  }, className: "rounded-md border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-input-bg,var(--sg-surface)))] px-2 py-1 text-xs text-[rgb(var(--sg-input-fg,var(--sg-text)))]", children: rowsPerPageOptions.map((option) => (_jsx("option", { value: option, children: option }, option))) })] })) : null] })) : null] }) }) }));
@@ -1 +1 @@
1
- {"version":3,"file":"SgInputPassword.d.ts","sourceRoot":"","sources":["../../src/inputs/SgInputPassword.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAInE,MAAM,MAAM,oBAAoB,GAAG,IAAI,CACrC,gBAAgB,EAChB,MAAM,GAAG,OAAO,GAAG,YAAY,GAAG,UAAU,GAAG,iBAAiB,GAAG,gBAAgB,CACpF,GAAG;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC9C,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,qCAAqC,CAAC,EAAE,OAAO,CAAC;IAChD,gCAAgC,CAAC,EAAE,OAAO,CAAC;IAC3C,iCAAiC,CAAC,EAAE,OAAO,CAAC;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,oBAAoB,CAAC,2CAgapE"}
1
+ {"version":3,"file":"SgInputPassword.d.ts","sourceRoot":"","sources":["../../src/inputs/SgInputPassword.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAInE,MAAM,MAAM,oBAAoB,GAAG,IAAI,CACrC,gBAAgB,EAChB,MAAM,GAAG,OAAO,GAAG,YAAY,GAAG,UAAU,GAAG,iBAAiB,GAAG,gBAAgB,CACpF,GAAG;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC9C,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,qCAAqC,CAAC,EAAE,OAAO,CAAC;IAChD,gCAAgC,CAAC,EAAE,OAAO,CAAC;IAC3C,iCAAiC,CAAC,EAAE,OAAO,CAAC;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,oBAAoB,CAAC,2CAmapE"}
@@ -220,9 +220,11 @@ export function SgInputPassword(props) {
220
220
  },
221
221
  ref: undefined
222
222
  };
223
- const setRef = (node) => {
223
+ const inputPropsExternalRefRef = React.useRef(undefined);
224
+ inputPropsExternalRefRef.current = inputProps?.ref;
225
+ const setRef = React.useCallback((node) => {
224
226
  inputRef.current = node;
225
- const ref = inputProps?.ref;
227
+ const ref = inputPropsExternalRefRef.current;
226
228
  if (!ref)
227
229
  return;
228
230
  if (typeof ref === "function") {
@@ -231,7 +233,7 @@ export function SgInputPassword(props) {
231
233
  else if (ref && typeof ref === "object" && "current" in ref) {
232
234
  ref.current = node;
233
235
  }
234
- };
236
+ }, []);
235
237
  const applyValue = (value) => {
236
238
  if (inputRef.current) {
237
239
  inputRef.current.value = value;
@@ -1 +1 @@
1
- {"version":3,"file":"SgInputText.d.ts","sourceRoot":"","sources":["../../src/inputs/SgInputText.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAwC,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAGlF,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG;IAC7C,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IACzC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,UAAU,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,KAAK,CAAC,sBAAsB,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,GAAG;QAC1D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;KACnC,CAAC,CAAC;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,WAAW,CAAC,CAAC;IACzE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC9C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACjD,CAAC;AAyeF,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,2CAsElD"}
1
+ {"version":3,"file":"SgInputText.d.ts","sourceRoot":"","sources":["../../src/inputs/SgInputText.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAwC,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAGlF,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG;IAC7C,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IACzC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,UAAU,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,KAAK,CAAC,sBAAsB,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,GAAG;QAC1D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;KACnC,CAAC,CAAC;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC,WAAW,CAAC,CAAC;IACzE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC9C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CACjD,CAAC;AAuhBF,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,2CAsElD"}
@@ -120,13 +120,16 @@ function SgInputTextBase(props) {
120
120
  const value = stripAffixes(inputProps.value ?? inputProps.defaultValue ?? "");
121
121
  return value.length;
122
122
  });
123
- React.useEffect(() => {
124
- const next = (inputRef.current?.value ?? "").length > 0;
125
- if (next !== isFilled)
126
- setIsFilled(next);
127
- const nextLength = (inputRef.current?.value ?? "").length;
123
+ const syncFilledStateFromDom = React.useCallback(() => {
124
+ const nextValue = inputRef.current?.value ?? "";
125
+ const nextFilled = nextValue.length > 0;
126
+ const nextLength = nextValue.length;
127
+ setIsFilled((prev) => (prev === nextFilled ? prev : nextFilled));
128
128
  setValueLength((prev) => (prev === nextLength ? prev : nextLength));
129
- }, [isFilled]);
129
+ }, []);
130
+ React.useEffect(() => {
131
+ syncFilledStateFromDom();
132
+ }, [syncFilledStateFromDom]);
130
133
  React.useEffect(() => {
131
134
  if (inputProps.value === undefined)
132
135
  return;
@@ -134,6 +137,27 @@ function SgInputTextBase(props) {
134
137
  setIsFilled(raw.length > 0);
135
138
  setValueLength(raw.length);
136
139
  }, [inputProps.value, stripAffixes]);
140
+ React.useEffect(() => {
141
+ const node = inputRef.current;
142
+ if (!node)
143
+ return;
144
+ const sync = () => {
145
+ syncFilledStateFromDom();
146
+ };
147
+ // Browsers/password managers may hydrate the value without dispatching React events.
148
+ const timers = [
149
+ window.setTimeout(sync, 0),
150
+ window.setTimeout(sync, 100),
151
+ window.setTimeout(sync, 300)
152
+ ];
153
+ node.addEventListener("input", sync);
154
+ node.addEventListener("change", sync);
155
+ return () => {
156
+ timers.forEach((timer) => window.clearTimeout(timer));
157
+ node.removeEventListener("input", sync);
158
+ node.removeEventListener("change", sync);
159
+ };
160
+ }, [syncFilledStateFromDom]);
137
161
  React.useLayoutEffect(() => {
138
162
  if (prefixRef.current) {
139
163
  const next = prefixRef.current.offsetWidth;
@@ -152,9 +176,11 @@ function SgInputTextBase(props) {
152
176
  setSuffixWidth(0);
153
177
  }
154
178
  }, [prefixText, suffixText, prefixWidth, suffixWidth]);
179
+ const forwardedRefRef = React.useRef(undefined);
180
+ forwardedRefRef.current = resolvedInputProps.ref;
155
181
  const setRefs = React.useCallback((node) => {
156
182
  inputRef.current = node;
157
- const ref = resolvedInputProps.ref;
183
+ const ref = forwardedRefRef.current;
158
184
  if (!ref)
159
185
  return;
160
186
  if (typeof ref === "function") {
@@ -163,7 +189,7 @@ function SgInputTextBase(props) {
163
189
  else if (typeof ref === "object") {
164
190
  ref.current = node;
165
191
  }
166
- }, [inputProps]);
192
+ }, []);
167
193
  const runValidation = React.useCallback((value) => {
168
194
  const required = props.required ?? false;
169
195
  if (!value && required) {
@@ -222,6 +248,7 @@ function SgInputTextBase(props) {
222
248
  props.onExit?.();
223
249
  };
224
250
  const handleFocus = () => {
251
+ syncFilledStateFromDom();
225
252
  props.onEnter?.();
226
253
  };
227
254
  const handleClear = () => {
@@ -316,7 +343,17 @@ function SgInputTextBase(props) {
316
343
  const outerLayoutStyle = labelPosition === "left"
317
344
  ? { ["--sg-input-label-width"]: resolvedLabelWidth }
318
345
  : undefined;
319
- const fieldNode = (_jsxs(_Fragment, { children: [_jsxs("div", { className: "relative", children: [prefixText ? (_jsx("span", { ref: prefixRef, className: "pointer-events-none absolute left-0 top-0 z-10 flex h-11 items-center rounded-l-md border border-border bg-muted/40 px-3 text-xs leading-none text-foreground/70", children: prefixText })) : null, props.prefixIcon ? (_jsx("span", { className: "pointer-events-none absolute left-3 top-1/2 z-10 -translate-y-1/2 text-foreground/60", children: props.prefixIcon })) : null, _jsx("input", { id: props.id, type: props.type ?? "text", placeholder: placeholder, className: props.className ?? finalClass, style: {
346
+ const fieldNode = (_jsxs(_Fragment, { children: [_jsx("style", { children: `
347
+ @keyframes sg-input-autofill-detect {
348
+ from {}
349
+ to {}
350
+ }
351
+
352
+ input:-webkit-autofill {
353
+ animation-name: sg-input-autofill-detect;
354
+ animation-duration: 0.01s;
355
+ }
356
+ ` }), _jsxs("div", { className: "relative", children: [prefixText ? (_jsx("span", { ref: prefixRef, className: "pointer-events-none absolute left-0 top-0 z-10 flex h-11 items-center rounded-l-md border border-border bg-muted/40 px-3 text-xs leading-none text-foreground/70", children: prefixText })) : null, props.prefixIcon ? (_jsx("span", { className: "pointer-events-none absolute left-3 top-1/2 z-10 -translate-y-1/2 text-foreground/60", children: props.prefixIcon })) : null, _jsx("input", { id: props.id, type: props.type ?? "text", placeholder: placeholder, className: props.className ?? finalClass, style: {
320
357
  borderRadius: resolvedBorderRadius,
321
358
  paddingLeft: prefixPaddingStyle,
322
359
  paddingRight: suffixPaddingStyle,
@@ -332,7 +369,7 @@ function SgInputTextBase(props) {
332
369
  ...(prefixText ? { borderTopLeftRadius: 0, borderBottomLeftRadius: 0, borderLeftWidth: 0 } : {}),
333
370
  ...(suffixText ? { borderTopRightRadius: 0, borderBottomRightRadius: 0, borderRightWidth: 0 } : {}),
334
371
  ...(resolvedInputProps.style ?? {})
335
- }, maxLength: props.maxLength, readOnly: props.readOnly, disabled: props.enabled === false, inputMode: props.textInputType ?? resolvedInputProps.inputMode, ...resolvedInputProps, ref: setRefs, onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus }), suffixText ? (_jsx("span", { ref: suffixRef, className: "pointer-events-none absolute right-0 top-0 z-10 flex h-11 items-center rounded-r-md border border-border bg-muted/40 px-3 text-xs leading-none text-foreground/70", children: suffixText })) : null, isFloatLabel ? (_jsxs("label", { htmlFor: props.id, className: [
372
+ }, maxLength: props.maxLength, readOnly: props.readOnly, disabled: props.enabled === false, inputMode: props.textInputType ?? resolvedInputProps.inputMode, ...resolvedInputProps, ref: setRefs, onChange: handleChange, onBlur: handleBlur, onFocus: handleFocus, onAnimationStart: syncFilledStateFromDom }), suffixText ? (_jsx("span", { ref: suffixRef, className: "pointer-events-none absolute right-0 top-0 z-10 flex h-11 items-center rounded-r-md border border-border bg-muted/40 px-3 text-xs leading-none text-foreground/70", children: suffixText })) : null, isFloatLabel ? (_jsxs("label", { htmlFor: props.id, className: [
336
373
  "absolute z-10 bg-[var(--sg-input-bg,hsl(var(--background)))] px-1 transition-all",
337
374
  isFilled ? "-top-2 text-xs" : "top-3 text-sm",
338
375
  hasError ? "text-[hsl(var(--destructive))]" : isFilled ? "text-[hsl(var(--primary))]" : "text-foreground/60",
@@ -1 +1 @@
1
- {"version":3,"file":"SgMenu.d.ts","sourceRoot":"","sources":["../../src/layout/SgMenu.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SgMenu.d.ts","sourceRoot":"","sources":["../../src/layout/SgMenu.tsx"],"names":[],"mappings":"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"}
@@ -196,6 +196,7 @@ export function SgMenu(props) {
196
196
  const closeOnNavigateResolved = closeOnNavigate ?? true;
197
197
  const searchEnabled = search?.enabled ?? false;
198
198
  const [searchValue, setSearchValue] = React.useState("");
199
+ const deferredSearchValue = React.useDeferredValue(searchValue);
199
200
  const menuRootRef = React.useRef(null);
200
201
  const sidebarShellRef = React.useRef(null);
201
202
  const menuHintAnchorRef = React.useRef(null);
@@ -207,8 +208,8 @@ export function SgMenu(props) {
207
208
  const dockHoverZoneRef = React.useRef(null);
208
209
  const searchEntries = React.useMemo(() => collectMenuSearchEntries(menu), [menu]);
209
210
  const autocompleteSource = React.useCallback((query) => resolveMenuAutocompleteItems(searchEntries, query), [searchEntries]);
210
- const filteredMenu = React.useMemo(() => (searchEnabled ? filterMenuNodes(menu, searchValue) : menu), [menu, searchEnabled, searchValue]);
211
- const hasSearch = searchEnabled && searchValue.trim().length > 0;
211
+ const filteredMenu = React.useMemo(() => (searchEnabled ? filterMenuNodes(menu, deferredSearchValue) : menu), [menu, searchEnabled, deferredSearchValue]);
212
+ const hasSearch = searchEnabled && deferredSearchValue.trim().length > 0;
212
213
  const effectiveMenuStyle = isCollapsed || hasSearch ? "panel" : resolvedMenuStyle;
213
214
  const layoutState = React.useMemo(() => resolveMenuLayoutState({
214
215
  dockMode,
@@ -1 +1 @@
1
- {"version":3,"file":"SgScreen.d.ts","sourceRoot":"","sources":["../../src/layout/SgScreen.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAO/B,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,GAAG;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CAAC;AAEF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,2CA8EtD;yBA9Ee,QAAQ"}
1
+ {"version":3,"file":"SgScreen.d.ts","sourceRoot":"","sources":["../../src/layout/SgScreen.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAO/B,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,GAAG;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CAAC;AAEF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,2CA0CtD;yBA1Ce,QAAQ"}