@seedgrid/fe-components 2026.11.3 → 2026.11.5
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.
- package/dist/ai/seedgrid-components.manifest.json +101 -11
- package/dist/buttons/SgButton.d.ts +41 -3
- package/dist/buttons/SgButton.d.ts.map +1 -1
- package/dist/buttons/SgButton.js +51 -5
- package/dist/buttons/SgButton.meta.d.ts.map +1 -1
- package/dist/buttons/SgButton.meta.js +27 -5
- package/dist/gadgets/calendar/SgCalendar.d.ts +6 -0
- package/dist/gadgets/calendar/SgCalendar.d.ts.map +1 -1
- package/dist/gadgets/calendar/SgCalendar.js +9 -5
- package/dist/gadgets/calendar/SgCalendar.meta.d.ts.map +1 -1
- package/dist/gadgets/calendar/SgCalendar.meta.js +1 -0
- package/dist/gadgets/clock/SgClock.d.ts +25 -1
- package/dist/gadgets/clock/SgClock.d.ts.map +1 -1
- package/dist/gadgets/clock/SgClock.js +18 -3
- package/dist/gadgets/clock/SgClock.meta.d.ts.map +1 -1
- package/dist/gadgets/clock/SgClock.meta.js +2 -1
- package/dist/generated/compiledStyles.d.ts +1 -1
- package/dist/generated/compiledStyles.d.ts.map +1 -1
- package/dist/generated/compiledStyles.js +1 -1
- package/dist/i18n/SgComponentsI18nProvider.meta.d.ts.map +1 -1
- package/dist/i18n/SgComponentsI18nProvider.meta.js +6 -3
- package/dist/i18n/useComponentsI18n.meta.d.ts.map +1 -1
- package/dist/i18n/useComponentsI18n.meta.js +8 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/inputs/SgDatatable.d.ts +7 -0
- package/dist/inputs/SgDatatable.d.ts.map +1 -1
- package/dist/inputs/SgDatatable.js +23 -11
- package/dist/inputs/SgDatatable.meta.d.ts.map +1 -1
- package/dist/inputs/SgDatatable.meta.js +1 -0
- package/dist/layout/SgToolBar.d.ts +6 -0
- package/dist/layout/SgToolBar.d.ts.map +1 -1
- package/dist/layout/SgToolBar.js +107 -5
- package/dist/layout/SgToolBar.meta.d.ts.map +1 -1
- package/dist/layout/SgToolBar.meta.js +8 -0
- package/dist/layout/toolbar-logic.d.ts +11 -0
- package/dist/layout/toolbar-logic.d.ts.map +1 -1
- package/dist/layout/toolbar-logic.js +25 -0
- package/dist/sandbox.cjs +55 -55
- package/dist/style.css +2 -2
- package/dist/wizard/SgWizard.d.ts +7 -0
- package/dist/wizard/SgWizard.d.ts.map +1 -1
- package/dist/wizard/SgWizard.js +11 -2
- package/dist/wizard/SgWizard.meta.d.ts.map +1 -1
- package/dist/wizard/SgWizard.meta.js +1 -0
- package/package.json +3 -3
|
@@ -226,7 +226,7 @@ function SgDatatableBase(props, imperativeRef) {
|
|
|
226
226
|
const i18n = useComponentsI18n();
|
|
227
227
|
const hasEnvironmentProvider = useHasSgEnvironmentProvider();
|
|
228
228
|
const persistence = useSgPersistence();
|
|
229
|
-
const { id, title, value, columns, dataKey, lazy = false, totalRecords: controlledTotalRecords, paginator = false, rows = 10, first, rowsPerPageOptions, onPage, infiniteScroll, onLoadMore, 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, mobileMode } = props;
|
|
229
|
+
const { id, title, value, columns, dataKey, lazy = false, totalRecords: controlledTotalRecords, paginator = false, rows = 10, first, rowsPerPageOptions, onPage, infiniteScroll, onLoadMore, sortField, sortOrder, onSort, removableSort = true, enabled = 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, mobileMode } = props;
|
|
230
230
|
const isFirstControlled = first !== undefined;
|
|
231
231
|
const isSortFieldControlled = sortField !== undefined;
|
|
232
232
|
const isSortOrderControlled = sortOrder !== undefined;
|
|
@@ -609,18 +609,24 @@ function SgDatatableBase(props, imperativeRef) {
|
|
|
609
609
|
return () => observer.disconnect();
|
|
610
610
|
}, [infiniteHasMore, loadMore, pagedRows.length]);
|
|
611
611
|
const commitSort = React.useCallback((nextSortField, nextSortOrder) => {
|
|
612
|
+
if (!enabled)
|
|
613
|
+
return;
|
|
612
614
|
if (!isSortFieldControlled)
|
|
613
615
|
setInternalSortField(nextSortField);
|
|
614
616
|
if (!isSortOrderControlled)
|
|
615
617
|
setInternalSortOrder(nextSortOrder);
|
|
616
618
|
onSort?.({ sortField: nextSortField, sortOrder: nextSortOrder });
|
|
617
|
-
}, [isSortFieldControlled, isSortOrderControlled, onSort]);
|
|
619
|
+
}, [enabled, isSortFieldControlled, isSortOrderControlled, onSort]);
|
|
618
620
|
const commitSelection = React.useCallback((nextSelection) => {
|
|
621
|
+
if (!enabled)
|
|
622
|
+
return;
|
|
619
623
|
if (!isSelectionControlled)
|
|
620
624
|
setInternalSelection(nextSelection);
|
|
621
625
|
onSelectionChange?.(nextSelection);
|
|
622
|
-
}, [isSelectionControlled, onSelectionChange]);
|
|
626
|
+
}, [enabled, isSelectionControlled, onSelectionChange]);
|
|
623
627
|
const commitFilters = React.useCallback((nextFilters, nextGlobalFilter) => {
|
|
628
|
+
if (!enabled)
|
|
629
|
+
return;
|
|
624
630
|
if (!isFiltersControlled)
|
|
625
631
|
setInternalFilters(nextFilters);
|
|
626
632
|
if (!isGlobalFilterControlled)
|
|
@@ -744,6 +750,8 @@ function SgDatatableBase(props, imperativeRef) {
|
|
|
744
750
|
const showAllColumnsLabel = resolveMessage(t(i18n, "components.datatable.showAllColumns"), "components.datatable.showAllColumns", "Show all");
|
|
745
751
|
const dragHandleLabel = resolveMessage(t(i18n, "components.datatable.dragToReorder"), "components.datatable.dragToReorder", "Drag to reorder");
|
|
746
752
|
const toggleColumnVisibility = React.useCallback((columnKey, forceVisible) => {
|
|
753
|
+
if (!enabled)
|
|
754
|
+
return;
|
|
747
755
|
setHiddenColumnsMap((prev) => {
|
|
748
756
|
const isCurrentlyHidden = Boolean(prev[columnKey]);
|
|
749
757
|
const willHide = forceVisible === undefined ? !isCurrentlyHidden : !forceVisible;
|
|
@@ -766,6 +774,8 @@ function SgDatatableBase(props, imperativeRef) {
|
|
|
766
774
|
});
|
|
767
775
|
}, []);
|
|
768
776
|
const restoreDefaultColumns = React.useCallback(() => {
|
|
777
|
+
if (!enabled)
|
|
778
|
+
return;
|
|
769
779
|
setColumnOrder(columnDescriptors.map((item) => item.key));
|
|
770
780
|
setHiddenColumnsMap(columnDescriptors.reduce((acc, item) => {
|
|
771
781
|
acc[item.key] = Boolean(item.column.hidden);
|
|
@@ -773,6 +783,8 @@ function SgDatatableBase(props, imperativeRef) {
|
|
|
773
783
|
}, {}));
|
|
774
784
|
}, [columnDescriptors]);
|
|
775
785
|
const showAllColumns = React.useCallback(() => {
|
|
786
|
+
if (!enabled)
|
|
787
|
+
return;
|
|
776
788
|
setHiddenColumnsMap((prev) => {
|
|
777
789
|
const next = { ...prev };
|
|
778
790
|
for (const item of columnDescriptors) {
|
|
@@ -811,7 +823,7 @@ function SgDatatableBase(props, imperativeRef) {
|
|
|
811
823
|
const sortDirectionLabel = resolveMessage(t(i18n, "components.datatable.sortDirection"), "components.datatable.sortDirection", "Reverse order");
|
|
812
824
|
const filtersPanelLabel = resolveMessage(t(i18n, "components.datatable.filters"), "components.datatable.filters", "Filters");
|
|
813
825
|
const resolvedTitle = (groupBoxProps.title ?? title ?? "").trim() || " ";
|
|
814
|
-
return (_jsx("div", { ref: rootRef, 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"
|
|
826
|
+
return (_jsx("div", { ref: rootRef, className: enabled ? className : cn(className, "opacity-60"), style: style, "aria-disabled": enabled ? undefined : true, "data-sg-enabled": enabled ? undefined : "false", 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, disabled: !enabled, 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", enabled: enabled, 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, disabled: !enabled, onClick: () => enabled && 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"
|
|
815
827
|
? 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: {
|
|
816
828
|
top: columnManagerPosition.top,
|
|
817
829
|
left: columnManagerPosition.left
|
|
@@ -841,7 +853,7 @@ function SgDatatableBase(props, imperativeRef) {
|
|
|
841
853
|
? "text-[rgb(var(--sg-muted))]"
|
|
842
854
|
: "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}`));
|
|
843
855
|
}) }) }), _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)
|
|
844
|
-
: null, cardsActive ? (_jsxs("div", { "data-sg-datatable-cards": "true", className: "space-y-2", children: [cardSortColumns.length > 0 || (showColumnFilters && cardFilterColumns.length > 0) ? (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [cardSortColumns.length > 0 ? (_jsxs(_Fragment, { children: [_jsxs("select", { "aria-label": sortByLabel, value: currentSortOrder === 0 || !currentSortField ? "" : currentSortField, onChange: (event) => {
|
|
856
|
+
: null, cardsActive ? (_jsxs("div", { "data-sg-datatable-cards": "true", className: "space-y-2", children: [cardSortColumns.length > 0 || (showColumnFilters && cardFilterColumns.length > 0) ? (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [cardSortColumns.length > 0 ? (_jsxs(_Fragment, { children: [_jsxs("select", { "aria-label": sortByLabel, disabled: !enabled, value: currentSortOrder === 0 || !currentSortField ? "" : currentSortField, onChange: (event) => {
|
|
845
857
|
const next = event.target.value;
|
|
846
858
|
if (!next)
|
|
847
859
|
commitSort(null, 0);
|
|
@@ -850,14 +862,14 @@ function SgDatatableBase(props, imperativeRef) {
|
|
|
850
862
|
}, className: "min-w-0 flex-1 rounded-md border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-input-bg,var(--sg-surface)))] px-2 py-2 text-sm text-[rgb(var(--sg-input-fg,var(--sg-text)))]", children: [_jsx("option", { value: "", children: sortNoneLabel }), cardSortColumns.map((column, columnIndex) => {
|
|
851
863
|
const key = (column.sortField ?? column.field);
|
|
852
864
|
return (_jsx("option", { value: key, children: cardHeaderLabel(column) }, `sort-${column.columnId ?? key}-${columnIndex}`));
|
|
853
|
-
})] }), _jsx(SgButton, { size: "sm", appearance: "outline", iconOnly: true, "aria-label": sortDirectionLabel, title: sortDirectionLabel, enabled: !(!currentSortField || currentSortOrder === 0), onClick: () => {
|
|
865
|
+
})] }), _jsx(SgButton, { size: "sm", appearance: "outline", iconOnly: true, "aria-label": sortDirectionLabel, title: sortDirectionLabel, enabled: enabled && !(!currentSortField || currentSortOrder === 0), onClick: () => {
|
|
854
866
|
if (!currentSortField)
|
|
855
867
|
return;
|
|
856
868
|
commitSort(currentSortField, currentSortOrder === 1 ? -1 : 1);
|
|
857
869
|
}, leftIcon: currentSortOrder === -1 ? _jsx(ArrowDown, { size: 16 }) : _jsx(ArrowUp, { size: 16 }) })] })) : null, showColumnFilters && cardFilterColumns.length > 0 ? (_jsx(SgButton, { size: "sm", appearance: "outline", "aria-expanded": isCardFiltersOpen, onClick: () => setIsCardFiltersOpen((prev) => !prev), children: filtersPanelLabel })) : null] })) : null, showColumnFilters && isCardFiltersOpen && cardFilterColumns.length > 0 ? (_jsx("div", { "data-sg-datatable-filters-panel": "true", className: "space-y-2 rounded-lg border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface))] p-3", children: cardFilterColumns.map((column, columnIndex) => {
|
|
858
870
|
const filterField = (column.filterField ?? column.field);
|
|
859
871
|
const filterValue = currentFilters[filterField] ?? "";
|
|
860
|
-
return (_jsxs("label", { className: "block space-y-1", children: [_jsx("span", { className: "text-xs font-semibold text-[rgb(var(--sg-muted))]", children: column.header }), _jsx("input", { value: filterValue, onChange: (event) => {
|
|
872
|
+
return (_jsxs("label", { className: "block space-y-1", children: [_jsx("span", { className: "text-xs font-semibold text-[rgb(var(--sg-muted))]", children: column.header }), _jsx("input", { value: filterValue, disabled: !enabled, onChange: (event) => {
|
|
861
873
|
const normalized = normalizeFilters({ ...currentFilters, [filterField]: event.target.value });
|
|
862
874
|
commitFilters(normalized, currentGlobalFilter);
|
|
863
875
|
}, 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-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))]" })] }, `cardfilter-${column.columnId ?? filterField}-${columnIndex}`));
|
|
@@ -871,7 +883,7 @@ function SgDatatableBase(props, imperativeRef) {
|
|
|
871
883
|
return;
|
|
872
884
|
}
|
|
873
885
|
handleRowSelection(rowData);
|
|
874
|
-
}, className: cn("rounded-lg border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface))] p-3", selectionMode ? "cursor-pointer" : "", stripedRows && absoluteRowIndex % 2 === 1 ? "bg-[rgb(var(--sg-primary-50))]" : "", selected ? "border-[rgb(var(--sg-primary-600))] bg-[rgb(var(--sg-primary-100))]" : "", customRowClass), children: [cardTitleColumn ? (_jsx("div", { "data-sg-card-title": "true", className: "mb-2 text-base font-semibold text-[rgb(var(--sg-text))]", children: renderCellContent(cardTitleColumn, rowData, absoluteRowIndex) })) : null, _jsx("dl", { className: "grid grid-cols-[auto_minmax(0,1fr)] gap-x-3 gap-y-1 text-sm", children: cardBodyColumns.map((column, columnIndex) => (_jsxs(React.Fragment, { children: [_jsx("dt", { className: "font-semibold text-[rgb(var(--sg-muted))]", children: column.header }), _jsx("dd", { className: cn("min-w-0 break-words text-[rgb(var(--sg-text))]", column.className), children: renderCellContent(column, rowData, absoluteRowIndex) })] }, `card-${column.columnId ?? column.field ?? columnIndex}-${absoluteRowIndex}`))) })] }, String(getRowIdentity(rowData, dataKey) ?? absoluteRowIndex)));
|
|
886
|
+
}, className: cn("rounded-lg border border-[rgb(var(--sg-border))] bg-[rgb(var(--sg-surface))] p-3", selectionMode && enabled ? "cursor-pointer" : "", stripedRows && absoluteRowIndex % 2 === 1 ? "bg-[rgb(var(--sg-primary-50))]" : "", selected ? "border-[rgb(var(--sg-primary-600))] bg-[rgb(var(--sg-primary-100))]" : "", customRowClass), children: [cardTitleColumn ? (_jsx("div", { "data-sg-card-title": "true", className: "mb-2 text-base font-semibold text-[rgb(var(--sg-text))]", children: renderCellContent(cardTitleColumn, rowData, absoluteRowIndex) })) : null, _jsx("dl", { className: "grid grid-cols-[auto_minmax(0,1fr)] gap-x-3 gap-y-1 text-sm", children: cardBodyColumns.map((column, columnIndex) => (_jsxs(React.Fragment, { children: [_jsx("dt", { className: "font-semibold text-[rgb(var(--sg-muted))]", children: column.header }), _jsx("dd", { className: cn("min-w-0 break-words text-[rgb(var(--sg-text))]", column.className), children: renderCellContent(column, rowData, absoluteRowIndex) })] }, `card-${column.columnId ?? column.field ?? columnIndex}-${absoluteRowIndex}`))) })] }, String(getRowIdentity(rowData, dataKey) ?? absoluteRowIndex)));
|
|
875
887
|
}) })), hasFooter ? (_jsx("dl", { "data-sg-card-footer": "true", className: "grid grid-cols-[auto_minmax(0,1fr)] gap-x-3 gap-y-1 rounded-lg bg-[rgb(var(--sg-primary-50))] p-3 text-sm font-semibold text-[rgb(var(--sg-text))]", children: visibleColumns
|
|
876
888
|
.filter((column) => column.footer !== undefined && !column.cardHidden)
|
|
877
889
|
.map((column, columnIndex) => (_jsxs(React.Fragment, { children: [_jsx("dt", { children: column.header }), _jsx("dd", { children: typeof column.footer === "function" ? column.footer(sortedRows) : column.footer })] }, `cardfoot-${column.columnId ?? column.field ?? columnIndex}`))) })) : 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) => {
|
|
@@ -883,11 +895,11 @@ function SgDatatableBase(props, imperativeRef) {
|
|
|
883
895
|
// direcao. `aria-hidden` no wrapper mantem o leitor de tela lendo so' o
|
|
884
896
|
// rotulo, como antes.
|
|
885
897
|
const sortIcon = !column.sortable ? null : isSorted && currentSortOrder === 1 ? (_jsx(ArrowUp, { size: 14 })) : isSorted && currentSortOrder === -1 ? (_jsx(ArrowDown, { size: 14 })) : (_jsx(ChevronsUpDown, { size: 14, className: "opacity-60" }));
|
|
886
|
-
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", className: "inline-flex items-center", children: sortIcon })] })) : (_jsx("span", { children: column.header })) }, `head-${column.columnId ?? column.field ?? columnIndex}`));
|
|
898
|
+
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", disabled: !enabled, 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", className: "inline-flex items-center", children: sortIcon })] })) : (_jsx("span", { children: column.header })) }, `head-${column.columnId ?? column.field ?? columnIndex}`));
|
|
887
899
|
}) }), shouldShowFiltersRow ? (_jsx("tr", { children: visibleColumns.map((column, columnIndex) => {
|
|
888
900
|
const filterField = column.filterField ?? column.field;
|
|
889
901
|
const filterValue = filterField ? currentFilters[filterField] ?? "" : "";
|
|
890
|
-
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) => {
|
|
902
|
+
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, disabled: !enabled, onChange: (event) => {
|
|
891
903
|
const nextFilters = {
|
|
892
904
|
...currentFilters,
|
|
893
905
|
[filterField]: event.target.value
|
|
@@ -905,7 +917,7 @@ function SgDatatableBase(props, imperativeRef) {
|
|
|
905
917
|
return;
|
|
906
918
|
}
|
|
907
919
|
handleRowSelection(rowData);
|
|
908
|
-
}, 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) => {
|
|
920
|
+
}, className: cn(selectionMode && enabled ? "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) => {
|
|
909
921
|
const cellField = column.field;
|
|
910
922
|
const customCellClass = typeof column.bodyClassName === "function"
|
|
911
923
|
? column.bodyClassName(rowData, absoluteRowIndex)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SgDatatable.meta.d.ts","sourceRoot":"","sources":["../../src/inputs/SgDatatable.meta.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE9D,eAAO,MAAM,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"SgDatatable.meta.d.ts","sourceRoot":"","sources":["../../src/inputs/SgDatatable.meta.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE9D,eAAO,MAAM,MAAM,EAAE,QAqCpB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,WAoBrB,CAAC"}
|
|
@@ -20,6 +20,7 @@ export const sgMeta = {
|
|
|
20
20
|
{ name: "rows", type: "number", description: "Linhas por pagina quando a paginacao esta ativa (os dados vao em value).", semanticRole: "behavior", bindable: true },
|
|
21
21
|
{ name: "selectionMode", type: "\"single\" | \"multiple\"", description: "Modo de selecao de linhas.", semanticRole: "behavior", bindable: true },
|
|
22
22
|
{ name: "loading", type: "boolean", default: false, description: "Indica estado de carregamento.", semanticRole: "appearance", bindable: true },
|
|
23
|
+
{ name: "enabled", type: "boolean", default: true, description: "Quando false, bloqueia as acoes que mudam estado: ordenacao, selecao de linhas, filtros (global e por coluna), limpar filtros e gerenciador de colunas. Paginacao, rolagem e carga de mais linhas continuam funcionando. Aparencia de desabilitado e aria-disabled.", semanticRole: "behavior", bindable: true },
|
|
23
24
|
{ name: "mobileMode", type: "\"scroll\" | \"cards\"", default: "(omitido = automatico)", description: "Comportamento em tela estreita. Omitido (padrao): cartoes quando o container fica abaixo de 600 px, tabela acima; cards: forca cartoes em qualquer largura; scroll: forca a tabela com rolagem horizontal. Nos cartoes mantem ordenacao, selecao, acoes, rodape e paginacao.", semanticRole: "behavior", bindable: true },
|
|
24
25
|
{ name: "infiniteScroll", type: "boolean", default: "(true nos cartoes, false na tabela)", description: "Rolagem infinita: sem paginador, ao chegar perto do fim da lista avanca a pagina (rows) e acrescenta os proximos registros, com indicador de carregando e de fim da lista. Padrao ligado quando a lista e exibida como cartoes (abaixo de 600 px no modo automatico) e desligado na tabela. Exige paginator. Com lazy, o pai acrescenta a proxima pagina a value (first/rows/page vem em onPage/onLoadMore).", semanticRole: "behavior", bindable: true },
|
|
25
26
|
{ name: "onLoadMore", type: "(event: SgDatatablePageEvent) => void", description: "Chamado (alem de onPage) quando a rolagem infinita pede a proxima pagina.", semanticRole: "event", bindable: false },
|
|
@@ -27,6 +27,12 @@ export type SgToolBarProps = {
|
|
|
27
27
|
collapsed?: boolean;
|
|
28
28
|
defaultCollapsed?: boolean;
|
|
29
29
|
onCollapsedChange?: (collapsed: boolean) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Quando a barra nao comporta todos os itens na largura (ou altura, na vertical) disponivel, os
|
|
32
|
+
* `SgToolbarIconButton` que nao cabem vao para um menu "..." (SgMenu). Abaixo de 600px de largura
|
|
33
|
+
* de tela o menu abre como painel inferior. Padrao: false. Ignorado com `buttonsPerDirection`.
|
|
34
|
+
*/
|
|
35
|
+
overflow?: boolean;
|
|
30
36
|
children?: React.ReactNode;
|
|
31
37
|
};
|
|
32
38
|
export type SgToolbarIconButtonProps = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SgToolBar.d.ts","sourceRoot":"","sources":["../../src/layout/SgToolBar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SgToolBar.d.ts","sourceRoot":"","sources":["../../src/layout/SgToolBar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAe/B,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,UAAU,CAAC;AAC7D,MAAM,MAAM,6BAA6B,GACrC,aAAa,GACb,eAAe,GACf,iBAAiB,GACjB,kBAAkB,CAAC;AACvB,MAAM,MAAM,iBAAiB,GACzB,SAAS,GACT,WAAW,GACX,SAAS,GACT,MAAM,GACN,SAAS,GACT,MAAM,GACN,QAAQ,GACR,OAAO,CAAC;AAEZ,MAAM,MAAM,aAAa,GAAG;IAC1B,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,oBAAoB,CAAC,EAAE,6BAA6B,CAAC;IACrD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAExD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAE3C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAEjD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,MAAM,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B,CAAC;AAgFF,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,2CA6jBxD;yBA7jBe,SAAS;;;AA+jBzB,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,QAAQ,CAAC,wBAAwB,GAAG;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,2CAiJpE;yBAlJe,mBAAmB"}
|
package/dist/layout/SgToolBar.js
CHANGED
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { createPortal } from "react-dom";
|
|
5
|
+
import { MoreHorizontal } from "lucide-react";
|
|
5
6
|
import { useSgDockLayout } from "./SgDockLayout";
|
|
6
7
|
import { useHasSgEnvironmentProvider, useSgPersistence } from "../environment/SgEnvironmentProvider";
|
|
7
8
|
import { t, useComponentsI18n } from "../i18n";
|
|
8
9
|
import { buildToolbarStorageKey, parseStoredPanelDragPosition } from "./drag-position";
|
|
9
|
-
import { buildToolbarLayoutState } from "./toolbar-logic";
|
|
10
|
+
import { buildToolbarLayoutState, resolveToolbarOverflow } from "./toolbar-logic";
|
|
11
|
+
import { SgMenu } from "./SgMenu";
|
|
12
|
+
import { SgPopup } from "../overlay/SgPopup";
|
|
10
13
|
function cn(...parts) {
|
|
11
14
|
return parts.filter(Boolean).join(" ");
|
|
12
15
|
}
|
|
@@ -72,7 +75,7 @@ export function SgToolBar(props) {
|
|
|
72
75
|
const hasEnvironmentProvider = useHasSgEnvironmentProvider();
|
|
73
76
|
const i18n = useComponentsI18n();
|
|
74
77
|
const { load: loadPersistedState, save: savePersistedState, clear: clearPersistedState } = useSgPersistence();
|
|
75
|
-
const { id, title, orientationDirection, buttonsPerDirection, bgColorTitle, bgColor, size, className, style, dockZone, draggable = false, freeDrag = false, defaultPosition, collapsible = true, collapsed, defaultCollapsed = false, onCollapsedChange, children } = props;
|
|
78
|
+
const { id, title, orientationDirection, buttonsPerDirection, bgColorTitle, bgColor, size, className, style, dockZone, draggable = false, freeDrag = false, defaultPosition, collapsible = true, collapsed, defaultCollapsed = false, onCollapsedChange, overflow = false, children } = props;
|
|
76
79
|
const dock = useSgDockLayout();
|
|
77
80
|
const inDock = !!dock;
|
|
78
81
|
const assignedZone = inDock ? dock.getToolbarZone(id) : null;
|
|
@@ -441,7 +444,8 @@ export function SgToolBar(props) {
|
|
|
441
444
|
const normalizedButtonsPerDirection = Number.isFinite(buttonsPerDirection) && typeof buttonsPerDirection === "number" && buttonsPerDirection > 0
|
|
442
445
|
? Math.floor(buttonsPerDirection)
|
|
443
446
|
: undefined;
|
|
444
|
-
const
|
|
447
|
+
const overflowActive = overflow && !normalizedButtonsPerDirection && showContent;
|
|
448
|
+
const content = showContent ? (_jsx("div", { className: cn("gap-2 p-2", overflowActive && "min-h-0 min-w-0 flex-1", normalizedButtonsPerDirection
|
|
445
449
|
? "grid"
|
|
446
450
|
: orientation === "horizontal"
|
|
447
451
|
? "flex flex-row"
|
|
@@ -452,7 +456,7 @@ export function SgToolBar(props) {
|
|
|
452
456
|
gridTemplateRows: `repeat(${normalizedButtonsPerDirection}, max-content)`,
|
|
453
457
|
gridAutoFlow: "column"
|
|
454
458
|
}
|
|
455
|
-
: undefined, children: children })) : null;
|
|
459
|
+
: undefined, children: overflowActive ? (_jsx(SgToolBarOverflowFlow, { horizontal: orientation === "horizontal", children: children })) : children })) : null;
|
|
456
460
|
const toolbar = (_jsx(SgToolbarOrientationContext.Provider, { value: orientation, children: _jsxs("div", { ref: containerRef, "data-sg-toolbar-root": "true", "data-sg-toolbar-id": id, className: cn("select-none rounded-xl border border-border bg-background shadow-sm", orientation === "horizontal" ? "inline-flex flex-row items-center" : "inline-flex flex-col items-center", className), style: {
|
|
457
461
|
width: size?.w,
|
|
458
462
|
height: size?.h,
|
|
@@ -464,7 +468,7 @@ export function SgToolBar(props) {
|
|
|
464
468
|
order: detachFromDockFlow ? undefined : toolbarRenderOrder,
|
|
465
469
|
zIndex: dragPos ? 1000 : undefined,
|
|
466
470
|
...style
|
|
467
|
-
}, onPointerDown: handlePointerDown, children: [openUp || openLeft ? content : null, (title || collapsible) && (_jsxs("div", { className: cn("flex items-center gap-2 px-2 py-1", orientation === "horizontal" ? "w-auto" : "w-full", orientation === "horizontal"
|
|
471
|
+
}, onPointerDown: handlePointerDown, children: [openUp || openLeft ? content : null, (title || collapsible) && (_jsxs("div", { className: cn("flex items-center gap-2 px-2 py-1", overflowActive && "shrink-0", orientation === "horizontal" ? "w-auto" : "w-full", orientation === "horizontal"
|
|
468
472
|
? showContent
|
|
469
473
|
? (openLeft ? "border-l border-border" : "border-r border-border")
|
|
470
474
|
: ""
|
|
@@ -559,6 +563,104 @@ export function SgToolbarIconButton(props) {
|
|
|
559
563
|
...style
|
|
560
564
|
}, children: [isLoading ? (_jsx("span", { className: "inline-flex size-4 shrink-0 animate-spin rounded-full border-2 border-current border-r-transparent" })) : icon && typeof icon !== "string" ? (_jsx("span", { className: "inline-flex shrink-0", children: icon })) : (_jsx("span", { className: "shrink-0 text-[10px] font-semibold", children: text?.slice(0, 2) })), hasVisibleLabel ? (_jsx("span", { className: "text-xs font-medium leading-none", children: label })) : null] }), hintNode] }));
|
|
561
565
|
}
|
|
566
|
+
const OVERFLOW_GAP = 8;
|
|
567
|
+
const OVERFLOW_NARROW_WIDTH = 600;
|
|
568
|
+
const useIsoLayoutEffect = typeof window !== "undefined" ? React.useLayoutEffect : React.useEffect;
|
|
569
|
+
function sameMetrics(a, b) {
|
|
570
|
+
return (!!a &&
|
|
571
|
+
a.more === b.more &&
|
|
572
|
+
a.available === b.available &&
|
|
573
|
+
a.extents.length === b.extents.length &&
|
|
574
|
+
a.extents.every((v, i) => v === b.extents[i]));
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Itens da toolbar com `overflow`: mede a largura (ResizeObserver) e move para o menu "..." os
|
|
578
|
+
* `SgToolbarIconButton` que nao cabem. Outros elementos que nao cabem ficam escondidos.
|
|
579
|
+
* Uma copia invisivel de todos os itens ("ghost") fornece os tamanhos naturais.
|
|
580
|
+
*/
|
|
581
|
+
function SgToolBarOverflowFlow(props) {
|
|
582
|
+
const { horizontal, children } = props;
|
|
583
|
+
const i18n = useComponentsI18n();
|
|
584
|
+
const items = React.Children.toArray(children);
|
|
585
|
+
const hostRef = React.useRef(null);
|
|
586
|
+
const ghostRef = React.useRef(null);
|
|
587
|
+
const moreRef = React.useRef(null);
|
|
588
|
+
const [metrics, setMetrics] = React.useState(null);
|
|
589
|
+
const [menuOpen, setMenuOpen] = React.useState(false);
|
|
590
|
+
const [narrow, setNarrow] = React.useState(false);
|
|
591
|
+
const measure = React.useCallback(() => {
|
|
592
|
+
const host = hostRef.current;
|
|
593
|
+
const ghost = ghostRef.current;
|
|
594
|
+
if (!host || !ghost)
|
|
595
|
+
return;
|
|
596
|
+
const sizes = Array.from(ghost.children).map((el) => horizontal ? el.offsetWidth : el.offsetHeight);
|
|
597
|
+
const more = sizes.pop() ?? 0;
|
|
598
|
+
const next = { extents: sizes, more, available: horizontal ? host.clientWidth : host.clientHeight };
|
|
599
|
+
setMetrics((prev) => (sameMetrics(prev, next) ? prev : next));
|
|
600
|
+
}, [horizontal]);
|
|
601
|
+
useIsoLayoutEffect(() => {
|
|
602
|
+
measure();
|
|
603
|
+
});
|
|
604
|
+
React.useEffect(() => {
|
|
605
|
+
const host = hostRef.current;
|
|
606
|
+
const ghost = ghostRef.current;
|
|
607
|
+
if (typeof ResizeObserver === "undefined") {
|
|
608
|
+
window.addEventListener("resize", measure);
|
|
609
|
+
return () => window.removeEventListener("resize", measure);
|
|
610
|
+
}
|
|
611
|
+
const observer = new ResizeObserver(() => measure());
|
|
612
|
+
if (host)
|
|
613
|
+
observer.observe(host);
|
|
614
|
+
if (ghost)
|
|
615
|
+
observer.observe(ghost);
|
|
616
|
+
return () => observer.disconnect();
|
|
617
|
+
}, [measure]);
|
|
618
|
+
const count = metrics && metrics.extents.length === items.length
|
|
619
|
+
? resolveToolbarOverflow({
|
|
620
|
+
extents: metrics.extents,
|
|
621
|
+
available: metrics.available,
|
|
622
|
+
gap: OVERFLOW_GAP,
|
|
623
|
+
overflowExtent: metrics.more
|
|
624
|
+
})
|
|
625
|
+
: items.length;
|
|
626
|
+
const showMore = count < items.length;
|
|
627
|
+
const hiddenNodes = [];
|
|
628
|
+
items.forEach((item, index) => {
|
|
629
|
+
if (index < count || !React.isValidElement(item) || item.type !== SgToolbarIconButton)
|
|
630
|
+
return;
|
|
631
|
+
const p = item.props;
|
|
632
|
+
hiddenNodes.push({
|
|
633
|
+
id: `sg-toolbar-overflow-${index}`,
|
|
634
|
+
label: p.label ?? p.hint ?? "",
|
|
635
|
+
hint: p.hint,
|
|
636
|
+
icon: p.icon,
|
|
637
|
+
enabled: p.enabled,
|
|
638
|
+
onClick: p.onClick ? () => { void p.onClick?.(); } : undefined
|
|
639
|
+
});
|
|
640
|
+
});
|
|
641
|
+
React.useEffect(() => {
|
|
642
|
+
if (!showMore && menuOpen)
|
|
643
|
+
setMenuOpen(false);
|
|
644
|
+
}, [showMore, menuOpen]);
|
|
645
|
+
const total = metrics ? metrics.extents.reduce((acc, v, i) => acc + v + (i > 0 ? OVERFLOW_GAP : 0), 0) : 0;
|
|
646
|
+
const openLabel = t(i18n, "components.menu.open");
|
|
647
|
+
const flexDir = horizontal ? "row" : "column";
|
|
648
|
+
return (_jsxs("div", { ref: hostRef, "data-sg-toolbar-overflow": "true", style: { position: "relative", minWidth: 0, minHeight: 0, flex: "1 1 0%", display: "flex" }, children: [metrics ? (_jsx("div", { "aria-hidden": "true", style: { flex: "none", width: horizontal ? total : 0, height: horizontal ? 0 : total } })) : null, _jsxs("div", { "data-sg-toolbar-overflow-items": "true", style: { display: "flex", flexDirection: flexDir, alignItems: "center", gap: OVERFLOW_GAP, minWidth: 0 }, children: [items.slice(0, count), showMore ? (_jsx("span", { ref: moreRef, "data-sg-toolbar-overflow-button": "true", style: { display: "inline-flex" }, children: _jsx(SgToolbarIconButton, { icon: _jsx(MoreHorizontal, { className: "size-4" }), hint: openLabel, onClick: () => {
|
|
649
|
+
setNarrow(typeof window !== "undefined" && window.innerWidth < OVERFLOW_NARROW_WIDTH);
|
|
650
|
+
setMenuOpen((open) => !open);
|
|
651
|
+
} }) })) : null] }), _jsx("div", { "aria-hidden": "true", style: {
|
|
652
|
+
position: "absolute",
|
|
653
|
+
left: 0,
|
|
654
|
+
top: 0,
|
|
655
|
+
width: 0,
|
|
656
|
+
height: 0,
|
|
657
|
+
overflow: "hidden",
|
|
658
|
+
visibility: "hidden",
|
|
659
|
+
pointerEvents: "none"
|
|
660
|
+
}, children: _jsxs("div", { ref: ghostRef, style: { display: "flex", flexDirection: flexDir, alignItems: "center", gap: OVERFLOW_GAP, width: "max-content" }, children: [items.map((item, index) => (_jsx("div", { style: { flex: "none" }, children: item }, index))), _jsx("div", { style: { flex: "none" }, children: _jsx(SgToolbarIconButton, { icon: _jsx(MoreHorizontal, { className: "size-4" }) }) })] }) }), showMore && menuOpen ? (_jsx(SgPopup, { open: true, onOpenChange: setMenuOpen, anchorRef: moreRef, placement: horizontal ? "bottom" : "right", align: "start", offset: 4, zIndex: 1300, minWidth: narrow ? 0 : 240, style: narrow
|
|
661
|
+
? { top: "auto", left: 0, right: 0, bottom: 0, width: "100%", borderRadius: "12px 12px 0 0" }
|
|
662
|
+
: undefined, children: _jsx(SgMenu, { menu: hiddenNodes, menuStyle: "inline", border: false, elevation: "none", expandedWidth: narrow ? "100%" : 240, ariaLabel: openLabel, onItemClick: () => setMenuOpen(false) }) })) : null] }));
|
|
663
|
+
}
|
|
562
664
|
function CollapseIcon(props) {
|
|
563
665
|
const { direction, collapsed } = props;
|
|
564
666
|
const arrowUp = "M6 15l6-6 6 6";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SgToolBar.meta.d.ts","sourceRoot":"","sources":["../../src/layout/SgToolBar.meta.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE9D,eAAO,MAAM,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"SgToolBar.meta.d.ts","sourceRoot":"","sources":["../../src/layout/SgToolBar.meta.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE9D,eAAO,MAAM,MAAM,EAAE,QAiHpB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,WAyBrB,CAAC"}
|
|
@@ -65,6 +65,14 @@ export const sgMeta = {
|
|
|
65
65
|
semanticRole: "behavior",
|
|
66
66
|
bindable: true
|
|
67
67
|
},
|
|
68
|
+
{
|
|
69
|
+
name: "overflow",
|
|
70
|
+
type: "boolean",
|
|
71
|
+
default: false,
|
|
72
|
+
description: "Move para um menu '...' os botoes que nao cabem na largura disponivel; abaixo de 600px abre como painel inferior.",
|
|
73
|
+
semanticRole: "behavior",
|
|
74
|
+
bindable: true
|
|
75
|
+
},
|
|
68
76
|
{
|
|
69
77
|
name: "children",
|
|
70
78
|
type: "ReactNode",
|
|
@@ -23,4 +23,15 @@ export declare function buildToolbarLayoutState(args: {
|
|
|
23
23
|
showLeadingCollapseButton: boolean;
|
|
24
24
|
collapseIconDirection: "left" | "right" | "up" | "down";
|
|
25
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* Overflow da SgToolBar (mesma regra do Flutter): quantos itens cabem no espaco principal.
|
|
28
|
+
* `extents` = tamanho de cada item no eixo principal; `overflowExtent` = tamanho do botao "..."
|
|
29
|
+
* (so conta se algum item ficar de fora). Devolve `extents.length` quando tudo cabe.
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveToolbarOverflow(args: {
|
|
32
|
+
extents: number[];
|
|
33
|
+
available: number;
|
|
34
|
+
gap: number;
|
|
35
|
+
overflowExtent: number;
|
|
36
|
+
}): number;
|
|
26
37
|
//# sourceMappingURL=toolbar-logic.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolbar-logic.d.ts","sourceRoot":"","sources":["../../src/layout/toolbar-logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,6BAA6B,EAAE,MAAM,aAAa,CAAC;AAEvF,wBAAgB,kCAAkC,CAChD,oBAAoB,EAAE,6BAA6B,GAClD;IAAE,WAAW,EAAE,oBAAoB,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,CAAA;CAAE,CAYpF;AAED,wBAAgB,sCAAsC,CACpD,oBAAoB,EAAE,6BAA6B,EACnD,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GACjD,6BAA6B,CAQ/B;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC5C,oBAAoB,EAAE,6BAA6B,CAAC;IACpD,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IACnD,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,YAAY,GAAG,IAAI,CAAC;IACnC,aAAa,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAC5D,WAAW,EAAE,OAAO,CAAC;CACtB,GAAG;IACF,kBAAkB,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IACjE,4BAA4B,EAAE,6BAA6B,CAAC;IAC5D,WAAW,EAAE,oBAAoB,CAAC;IAClC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC;IAC5C,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,yBAAyB,EAAE,OAAO,CAAC;IACnC,qBAAqB,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC;CACzD,CAoBA"}
|
|
1
|
+
{"version":3,"file":"toolbar-logic.d.ts","sourceRoot":"","sources":["../../src/layout/toolbar-logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,6BAA6B,EAAE,MAAM,aAAa,CAAC;AAEvF,wBAAgB,kCAAkC,CAChD,oBAAoB,EAAE,6BAA6B,GAClD;IAAE,WAAW,EAAE,oBAAoB,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,CAAA;CAAE,CAYpF;AAED,wBAAgB,sCAAsC,CACpD,oBAAoB,EAAE,6BAA6B,EACnD,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GACjD,6BAA6B,CAQ/B;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC5C,oBAAoB,EAAE,6BAA6B,CAAC;IACpD,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IACnD,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,YAAY,GAAG,IAAI,CAAC;IACnC,aAAa,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAC5D,WAAW,EAAE,OAAO,CAAC;CACtB,GAAG;IACF,kBAAkB,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IACjE,4BAA4B,EAAE,6BAA6B,CAAC;IAC5D,WAAW,EAAE,oBAAoB,CAAC;IAClC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC;IAC5C,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,yBAAyB,EAAE,OAAO,CAAC;IACnC,qBAAqB,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC;CACzD,CAoBA;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;CACxB,GAAG,MAAM,CAeT"}
|
|
@@ -36,3 +36,28 @@ export function buildToolbarLayoutState(args) {
|
|
|
36
36
|
collapseIconDirection: resolvedOrientationDirection === "horizontal-right" ? "right" : direction
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Overflow da SgToolBar (mesma regra do Flutter): quantos itens cabem no espaco principal.
|
|
41
|
+
* `extents` = tamanho de cada item no eixo principal; `overflowExtent` = tamanho do botao "..."
|
|
42
|
+
* (so conta se algum item ficar de fora). Devolve `extents.length` quando tudo cabe.
|
|
43
|
+
*/
|
|
44
|
+
export function resolveToolbarOverflow(args) {
|
|
45
|
+
const { extents, available, gap, overflowExtent } = args;
|
|
46
|
+
if (!Number.isFinite(available))
|
|
47
|
+
return extents.length;
|
|
48
|
+
let total = 0;
|
|
49
|
+
for (let i = 0; i < extents.length; i++)
|
|
50
|
+
total += (extents[i] ?? 0) + (i > 0 ? gap : 0);
|
|
51
|
+
if (total <= available + 0.01)
|
|
52
|
+
return extents.length;
|
|
53
|
+
let used = 0;
|
|
54
|
+
let count = 0;
|
|
55
|
+
for (let i = 0; i < extents.length; i++) {
|
|
56
|
+
const next = used + (extents[i] ?? 0) + (count > 0 ? gap : 0);
|
|
57
|
+
if (next + gap + overflowExtent > available + 0.01)
|
|
58
|
+
break;
|
|
59
|
+
used = next;
|
|
60
|
+
count++;
|
|
61
|
+
}
|
|
62
|
+
return count;
|
|
63
|
+
}
|