@seedgrid/fe-components 2026.11.4 → 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.
Files changed (33) hide show
  1. package/dist/ai/seedgrid-components.manifest.json +74 -11
  2. package/dist/buttons/SgButton.d.ts +41 -3
  3. package/dist/buttons/SgButton.d.ts.map +1 -1
  4. package/dist/buttons/SgButton.js +51 -5
  5. package/dist/buttons/SgButton.meta.d.ts.map +1 -1
  6. package/dist/buttons/SgButton.meta.js +27 -5
  7. package/dist/gadgets/clock/SgClock.d.ts +25 -1
  8. package/dist/gadgets/clock/SgClock.d.ts.map +1 -1
  9. package/dist/gadgets/clock/SgClock.js +18 -3
  10. package/dist/gadgets/clock/SgClock.meta.d.ts.map +1 -1
  11. package/dist/gadgets/clock/SgClock.meta.js +2 -1
  12. package/dist/generated/compiledStyles.d.ts +1 -1
  13. package/dist/generated/compiledStyles.d.ts.map +1 -1
  14. package/dist/generated/compiledStyles.js +1 -1
  15. package/dist/i18n/SgComponentsI18nProvider.meta.d.ts.map +1 -1
  16. package/dist/i18n/SgComponentsI18nProvider.meta.js +6 -3
  17. package/dist/i18n/useComponentsI18n.meta.d.ts.map +1 -1
  18. package/dist/i18n/useComponentsI18n.meta.js +8 -2
  19. package/dist/index.d.ts +2 -2
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +1 -1
  22. package/dist/layout/SgToolBar.d.ts +6 -0
  23. package/dist/layout/SgToolBar.d.ts.map +1 -1
  24. package/dist/layout/SgToolBar.js +107 -5
  25. package/dist/layout/SgToolBar.meta.d.ts.map +1 -1
  26. package/dist/layout/SgToolBar.meta.js +8 -0
  27. package/dist/layout/toolbar-logic.d.ts +11 -0
  28. package/dist/layout/toolbar-logic.d.ts.map +1 -1
  29. package/dist/layout/toolbar-logic.js +25 -0
  30. package/dist/sandbox.cjs +58 -58
  31. package/dist/style.css +2 -2
  32. package/dist/wizard/SgWizard.js +1 -1
  33. package/package.json +3 -3
@@ -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 content = showContent ? (_jsx("div", { className: cn("gap-2 p-2", normalizedButtonsPerDirection
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,QAyGpB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,WAyBrB,CAAC"}
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
+ }