@seedgrid/fe-components 2026.3.2 → 2026.3.3
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/gadgets/qr-code/SgQRCode.d.ts.map +1 -1
- package/dist/gadgets/qr-code/SgQRCode.js +22 -48
- package/dist/layout/SgMenu.d.ts +1 -0
- package/dist/layout/SgMenu.d.ts.map +1 -1
- package/dist/layout/SgMenu.js +120 -13
- package/dist/layout/SgPageControl.d.ts +1 -0
- package/dist/layout/SgPageControl.d.ts.map +1 -1
- package/dist/layout/SgPageControl.js +1 -1
- package/dist/others/SgPlayground.d.ts +12 -0
- package/dist/others/SgPlayground.d.ts.map +1 -1
- package/dist/others/SgPlayground.js +545 -23
- package/package.json +6 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SgQRCode.d.ts","sourceRoot":"","sources":["../../../src/gadgets/qr-code/SgQRCode.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SgQRCode.d.ts","sourceRoot":"","sources":["../../../src/gadgets/qr-code/SgQRCode.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAyC/B,MAAM,MAAM,4BAA4B,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEjE,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,GAAG;IACnF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB,CAAC,EAAE,4BAA4B,CAAC;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChC,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC1C,CAAC;AAEF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,kDA8FtD;yBA9Fe,QAAQ"}
|
|
@@ -1,70 +1,44 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import
|
|
4
|
+
import { QRCodeSVG } from "qrcode.react";
|
|
5
5
|
function cn(...parts) {
|
|
6
6
|
return parts.filter(Boolean).join(" ");
|
|
7
7
|
}
|
|
8
|
+
class QrErrorBoundary extends React.Component {
|
|
9
|
+
state = { hasError: false };
|
|
10
|
+
static getDerivedStateFromError() {
|
|
11
|
+
return { hasError: true };
|
|
12
|
+
}
|
|
13
|
+
componentDidCatch(error) {
|
|
14
|
+
this.props.onError?.(error);
|
|
15
|
+
}
|
|
16
|
+
componentDidUpdate(prevProps) {
|
|
17
|
+
if (prevProps.resetKey !== this.props.resetKey && this.state.hasError) {
|
|
18
|
+
this.setState({ hasError: false });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
render() {
|
|
22
|
+
if (this.state.hasError)
|
|
23
|
+
return this.props.fallback;
|
|
24
|
+
return this.props.children;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
8
27
|
export function SgQRCode(props) {
|
|
9
28
|
const { value, size = 220, margin = 2, fgColor = "#000000", bgColor = "#FFFFFF", errorCorrectionLevel = "H", logoSrc, logoAlt = "Logo", logoSize, logoPadding = 6, logoBackgroundColor = "#FFFFFF", logoBorderRadius = 12, imageClassName, logoClassName, emptyFallback, onGenerateError, className, style, ...rest } = props;
|
|
10
|
-
const [qrDataUrl, setQrDataUrl] = React.useState("");
|
|
11
|
-
const [hasError, setHasError] = React.useState(false);
|
|
12
29
|
const normalizedValue = value?.trim() ?? "";
|
|
13
30
|
const safeSize = Math.max(64, Math.round(size));
|
|
14
31
|
const safeMargin = Math.max(0, Math.round(margin));
|
|
15
32
|
const safeLogoPadding = Math.max(0, Math.round(logoPadding));
|
|
16
33
|
const safeLogoSize = Math.max(18, Math.min(safeSize, Math.round(logoSize ?? safeSize * 0.22)));
|
|
17
34
|
const logoContainerSize = safeLogoSize + safeLogoPadding * 2;
|
|
18
|
-
|
|
19
|
-
let active = true;
|
|
20
|
-
if (!normalizedValue) {
|
|
21
|
-
setQrDataUrl("");
|
|
22
|
-
setHasError(false);
|
|
23
|
-
return () => {
|
|
24
|
-
active = false;
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
QRCode.toDataURL(normalizedValue, {
|
|
28
|
-
width: safeSize,
|
|
29
|
-
margin: safeMargin,
|
|
30
|
-
color: {
|
|
31
|
-
dark: fgColor,
|
|
32
|
-
light: bgColor
|
|
33
|
-
},
|
|
34
|
-
errorCorrectionLevel
|
|
35
|
-
})
|
|
36
|
-
.then((dataUrl) => {
|
|
37
|
-
if (!active)
|
|
38
|
-
return;
|
|
39
|
-
setQrDataUrl(dataUrl);
|
|
40
|
-
setHasError(false);
|
|
41
|
-
})
|
|
42
|
-
.catch((cause) => {
|
|
43
|
-
if (!active)
|
|
44
|
-
return;
|
|
45
|
-
const error = cause instanceof Error ? cause : new Error("Failed to generate QR code");
|
|
46
|
-
setQrDataUrl("");
|
|
47
|
-
setHasError(true);
|
|
48
|
-
onGenerateError?.(error);
|
|
49
|
-
});
|
|
50
|
-
return () => {
|
|
51
|
-
active = false;
|
|
52
|
-
};
|
|
53
|
-
}, [
|
|
54
|
-
normalizedValue,
|
|
55
|
-
safeSize,
|
|
56
|
-
safeMargin,
|
|
57
|
-
fgColor,
|
|
58
|
-
bgColor,
|
|
59
|
-
errorCorrectionLevel,
|
|
60
|
-
onGenerateError
|
|
61
|
-
]);
|
|
35
|
+
const qrResetKey = `${normalizedValue}|${safeSize}|${safeMargin}|${fgColor}|${bgColor}|${errorCorrectionLevel}`;
|
|
62
36
|
if (!normalizedValue) {
|
|
63
37
|
if (!emptyFallback)
|
|
64
38
|
return null;
|
|
65
39
|
return (_jsx("div", { className: cn("inline-flex items-center justify-center", className), style: { width: safeSize, height: safeSize, ...style }, ...rest, children: emptyFallback }));
|
|
66
40
|
}
|
|
67
|
-
return (_jsxs("div", { className: cn("relative inline-flex items-center justify-center", className), style: { width: safeSize, height: safeSize, ...style }, ...rest, children: [
|
|
41
|
+
return (_jsxs("div", { className: cn("relative inline-flex items-center justify-center", className), style: { width: safeSize, height: safeSize, ...style }, ...rest, children: [_jsx(QrErrorBoundary, { resetKey: qrResetKey, onError: onGenerateError, fallback: _jsx("div", { className: "h-full w-full animate-pulse rounded-md bg-muted/40", "aria-hidden": "true" }), children: _jsx(QRCodeSVG, { value: normalizedValue, size: safeSize, marginSize: safeMargin, fgColor: fgColor, bgColor: bgColor, level: errorCorrectionLevel, title: "QR Code", className: cn("block h-full w-full", imageClassName) }) }), logoSrc ? (_jsx("span", { className: cn("absolute inline-flex items-center justify-center overflow-hidden", logoClassName), style: {
|
|
68
42
|
width: logoContainerSize,
|
|
69
43
|
height: logoContainerSize,
|
|
70
44
|
padding: safeLogoPadding,
|
package/dist/layout/SgMenu.d.ts
CHANGED
|
@@ -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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"}
|
package/dist/layout/SgMenu.js
CHANGED
|
@@ -290,6 +290,8 @@ export function SgMenu(props) {
|
|
|
290
290
|
const [searchValue, setSearchValue] = React.useState("");
|
|
291
291
|
const menuRootRef = React.useRef(null);
|
|
292
292
|
const sidebarShellRef = React.useRef(null);
|
|
293
|
+
const menuHintAnchorRef = React.useRef(null);
|
|
294
|
+
const [menuHint, setMenuHint] = React.useState(null);
|
|
293
295
|
const [dockDragActive, setDockDragActive] = React.useState(false);
|
|
294
296
|
const [horizontalDockAlign, setHorizontalDockAlign] = React.useState(null);
|
|
295
297
|
const dockDragStartRef = React.useRef(null);
|
|
@@ -326,6 +328,41 @@ export function SgMenu(props) {
|
|
|
326
328
|
const isVerticalDockZone = effectiveDockZone === "left" || effectiveDockZone === "right";
|
|
327
329
|
const tieredOpenToLeft = resolvedPosition === "right" ||
|
|
328
330
|
(isHorizontalDockZone && horizontalDockAlign === "right");
|
|
331
|
+
const hideMenuHint = React.useCallback(() => {
|
|
332
|
+
menuHintAnchorRef.current = null;
|
|
333
|
+
setMenuHint(null);
|
|
334
|
+
}, []);
|
|
335
|
+
const resolveMenuHintPosition = React.useCallback((anchor) => {
|
|
336
|
+
if (!anchor.target.isConnected)
|
|
337
|
+
return null;
|
|
338
|
+
const rect = anchor.target.getBoundingClientRect();
|
|
339
|
+
if (anchor.placement === "right") {
|
|
340
|
+
return {
|
|
341
|
+
x: rect.right + 8,
|
|
342
|
+
y: rect.top + (rect.height / 2)
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
return {
|
|
346
|
+
x: rect.left + (rect.width / 2),
|
|
347
|
+
y: rect.top - 8
|
|
348
|
+
};
|
|
349
|
+
}, []);
|
|
350
|
+
const showMenuHint = React.useCallback((target, text, placement = "top") => {
|
|
351
|
+
if (!text)
|
|
352
|
+
return;
|
|
353
|
+
const anchor = { target, text, placement };
|
|
354
|
+
menuHintAnchorRef.current = anchor;
|
|
355
|
+
const nextPosition = resolveMenuHintPosition(anchor);
|
|
356
|
+
if (!nextPosition) {
|
|
357
|
+
hideMenuHint();
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
setMenuHint({
|
|
361
|
+
text: anchor.text,
|
|
362
|
+
placement: anchor.placement,
|
|
363
|
+
...nextPosition
|
|
364
|
+
});
|
|
365
|
+
}, [hideMenuHint, resolveMenuHintPosition]);
|
|
329
366
|
const [localActiveId, setLocalActiveId] = React.useState(selection?.activeId);
|
|
330
367
|
const [tieredPath, setTieredPath] = React.useState([]);
|
|
331
368
|
const [megaActiveId, setMegaActiveId] = React.useState(menu[0]?.id);
|
|
@@ -431,6 +468,40 @@ export function SgMenu(props) {
|
|
|
431
468
|
document.addEventListener("pointerdown", handlePointerDown);
|
|
432
469
|
return () => document.removeEventListener("pointerdown", handlePointerDown);
|
|
433
470
|
}, [effectiveMenuStyle]);
|
|
471
|
+
const hasVisibleMenuHint = menuHint !== null;
|
|
472
|
+
React.useEffect(() => {
|
|
473
|
+
if (!hasVisibleMenuHint || !menuHintAnchorRef.current)
|
|
474
|
+
return;
|
|
475
|
+
const reposition = () => {
|
|
476
|
+
const anchor = menuHintAnchorRef.current;
|
|
477
|
+
if (!anchor)
|
|
478
|
+
return;
|
|
479
|
+
const nextPosition = resolveMenuHintPosition(anchor);
|
|
480
|
+
if (!nextPosition) {
|
|
481
|
+
hideMenuHint();
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
setMenuHint({
|
|
485
|
+
text: anchor.text,
|
|
486
|
+
placement: anchor.placement,
|
|
487
|
+
...nextPosition
|
|
488
|
+
});
|
|
489
|
+
};
|
|
490
|
+
reposition();
|
|
491
|
+
window.addEventListener("scroll", reposition, true);
|
|
492
|
+
window.addEventListener("resize", reposition);
|
|
493
|
+
return () => {
|
|
494
|
+
window.removeEventListener("scroll", reposition, true);
|
|
495
|
+
window.removeEventListener("resize", reposition);
|
|
496
|
+
};
|
|
497
|
+
}, [hasVisibleMenuHint, hideMenuHint, resolveMenuHintPosition]);
|
|
498
|
+
React.useEffect(() => {
|
|
499
|
+
const anchor = menuHintAnchorRef.current;
|
|
500
|
+
if (!anchor)
|
|
501
|
+
return;
|
|
502
|
+
if (!anchor.target.isConnected)
|
|
503
|
+
hideMenuHint();
|
|
504
|
+
}, [filteredMenu, effectiveMenuStyle, isCollapsed, drawerOpen, pinnedState, hideMenuHint]);
|
|
434
505
|
const toggleExpanded = React.useCallback((nodeId) => {
|
|
435
506
|
setExpandedIds((prev) => {
|
|
436
507
|
const next = new Set(prev);
|
|
@@ -454,6 +525,7 @@ export function SgMenu(props) {
|
|
|
454
525
|
const activateNode = React.useCallback((node) => {
|
|
455
526
|
if (node.disabled)
|
|
456
527
|
return;
|
|
528
|
+
hideMenuHint();
|
|
457
529
|
onItemClick?.(node);
|
|
458
530
|
setLocalActiveId(node.id);
|
|
459
531
|
const hasUrl = typeof node.url === "string" && node.url.length > 0;
|
|
@@ -477,7 +549,8 @@ export function SgMenu(props) {
|
|
|
477
549
|
onNavigate,
|
|
478
550
|
pinnedState,
|
|
479
551
|
setDrawerOpen,
|
|
480
|
-
variant
|
|
552
|
+
variant,
|
|
553
|
+
hideMenuHint
|
|
481
554
|
]);
|
|
482
555
|
const handleDockDragPointerDown = React.useCallback((event) => {
|
|
483
556
|
if (event.button !== 0)
|
|
@@ -654,11 +727,15 @@ export function SgMenu(props) {
|
|
|
654
727
|
const disabled = !!node.disabled;
|
|
655
728
|
const iconNode = resolveIcon(node);
|
|
656
729
|
const hideChildren = isCollapsed;
|
|
730
|
+
const nodeHint = node.hint ?? (isCollapsed ? node.label : undefined);
|
|
731
|
+
const nodeHintPlacement = "right";
|
|
657
732
|
return (_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: cn("group flex items-center rounded-md", densityCfg.row, densityCfg.gap, isExactActive
|
|
658
733
|
? "bg-primary/15 text-primary"
|
|
659
734
|
: isBranchActive
|
|
660
735
|
? "bg-muted/60 text-foreground"
|
|
661
|
-
: "text-foreground hover:bg-muted/60", disabled ? "cursor-not-allowed opacity-55" : ""), style: isCollapsed ? undefined : { paddingLeft: 8 + depth * indent },
|
|
736
|
+
: "text-foreground hover:bg-muted/60", disabled ? "cursor-not-allowed opacity-55" : ""), style: isCollapsed ? undefined : { paddingLeft: 8 + depth * indent }, onMouseEnter: nodeHint
|
|
737
|
+
? (event) => showMenuHint(event.currentTarget, nodeHint, nodeHintPlacement)
|
|
738
|
+
: undefined, onMouseLeave: nodeHint ? hideMenuHint : undefined, children: [_jsxs("button", { ref: (el) => {
|
|
662
739
|
itemRefs.current[node.id] = el;
|
|
663
740
|
}, "data-sg-menu-node": node.id, type: "button", "aria-disabled": disabled || undefined, "aria-current": isExactActive ? "page" : undefined, onFocus: () => setFocusedId(node.id), onClick: () => {
|
|
664
741
|
if (disabled)
|
|
@@ -681,6 +758,8 @@ export function SgMenu(props) {
|
|
|
681
758
|
hasSearch,
|
|
682
759
|
indent,
|
|
683
760
|
isCollapsed,
|
|
761
|
+
hideMenuHint,
|
|
762
|
+
showMenuHint,
|
|
684
763
|
toggleExpanded
|
|
685
764
|
]);
|
|
686
765
|
const renderFlatAction = React.useCallback((node, className) => {
|
|
@@ -688,7 +767,7 @@ export function SgMenu(props) {
|
|
|
688
767
|
const isBranchActive = activeSets.branch.has(node.id);
|
|
689
768
|
const hasChildren = !!node.children?.length;
|
|
690
769
|
const iconNode = resolveIcon(node);
|
|
691
|
-
return (_jsxs("button", { type: "button", disabled: node.disabled, "aria-current": isExactActive ? "page" : undefined, onClick: () => {
|
|
770
|
+
return (_jsxs("button", { type: "button", disabled: node.disabled, "aria-current": isExactActive ? "page" : undefined, onMouseEnter: node.hint ? (event) => showMenuHint(event.currentTarget, node.hint) : undefined, onMouseLeave: node.hint ? hideMenuHint : undefined, onClick: () => {
|
|
692
771
|
if (node.disabled)
|
|
693
772
|
return;
|
|
694
773
|
if (hasChildren && !node.url && !node.onClick)
|
|
@@ -699,7 +778,7 @@ export function SgMenu(props) {
|
|
|
699
778
|
: isBranchActive
|
|
700
779
|
? "bg-muted/60 text-foreground"
|
|
701
780
|
: "text-foreground hover:bg-muted/60", node.disabled ? "cursor-not-allowed opacity-55" : "", className), children: [_jsx("span", { className: cn("inline-flex shrink-0 items-center justify-center rounded", densityCfg.icon, iconNode ? "" : "bg-muted text-[10px] font-semibold"), children: iconNode ?? firstChars(node.label, 1) }), _jsx("span", { className: "min-w-0 flex-1 truncate", children: node.label }), hasChildren ? _jsx(ChevronRight, { className: "size-4 shrink-0 text-muted-foreground" }) : null] }, node.id));
|
|
702
|
-
}, [activateNode, activeSets.branch, activeSets.exact, densityCfg.icon]);
|
|
781
|
+
}, [activateNode, activeSets.branch, activeSets.exact, densityCfg.icon, hideMenuHint, showMenuHint]);
|
|
703
782
|
const renderTieredLevels = React.useCallback((nodes, depth) => {
|
|
704
783
|
if (!nodes.length)
|
|
705
784
|
return null;
|
|
@@ -712,7 +791,9 @@ export function SgMenu(props) {
|
|
|
712
791
|
const isOpen = activeIdAtDepth === node.id;
|
|
713
792
|
const isExactActive = activeSets.exact.has(node.id);
|
|
714
793
|
const iconNode = resolveIcon(node);
|
|
715
|
-
return (_jsxs("button", { type: "button", disabled: node.disabled, "aria-current": isExactActive ? "page" : undefined, onMouseEnter: () => {
|
|
794
|
+
return (_jsxs("button", { type: "button", disabled: node.disabled, "aria-current": isExactActive ? "page" : undefined, onMouseEnter: (event) => {
|
|
795
|
+
if (node.hint)
|
|
796
|
+
showMenuHint(event.currentTarget, node.hint);
|
|
716
797
|
if (!openSubmenuOnHover)
|
|
717
798
|
return;
|
|
718
799
|
if (!hasChildren) {
|
|
@@ -720,7 +801,7 @@ export function SgMenu(props) {
|
|
|
720
801
|
return;
|
|
721
802
|
}
|
|
722
803
|
setTieredPath((prev) => [...prev.slice(0, depth), node.id]);
|
|
723
|
-
}, onClick: () => {
|
|
804
|
+
}, onMouseLeave: node.hint ? hideMenuHint : undefined, onClick: () => {
|
|
724
805
|
if (node.disabled)
|
|
725
806
|
return;
|
|
726
807
|
if (hasChildren) {
|
|
@@ -739,7 +820,16 @@ export function SgMenu(props) {
|
|
|
739
820
|
}) }), activeNode?.children?.length
|
|
740
821
|
? renderTieredLevels(activeNode.children, depth + 1)
|
|
741
822
|
: null] }));
|
|
742
|
-
}, [
|
|
823
|
+
}, [
|
|
824
|
+
activateNode,
|
|
825
|
+
activeSets.exact,
|
|
826
|
+
densityCfg.icon,
|
|
827
|
+
hideMenuHint,
|
|
828
|
+
openSubmenuOnHover,
|
|
829
|
+
showMenuHint,
|
|
830
|
+
tieredOpenToLeft,
|
|
831
|
+
tieredPath
|
|
832
|
+
]);
|
|
743
833
|
const renderMegaColumns = React.useCallback((nodes) => {
|
|
744
834
|
if (!nodes.length) {
|
|
745
835
|
return _jsx("div", { className: "text-sm text-muted-foreground", children: "No items found." });
|
|
@@ -763,7 +853,12 @@ export function SgMenu(props) {
|
|
|
763
853
|
const hasChildren = !!node.children?.length;
|
|
764
854
|
const active = activeMegaNode?.id === node.id;
|
|
765
855
|
const iconNode = resolveIcon(node);
|
|
766
|
-
return (_jsxs("button", { type: "button", disabled: node.disabled, onMouseEnter: () =>
|
|
856
|
+
return (_jsxs("button", { type: "button", disabled: node.disabled, onMouseEnter: (event) => {
|
|
857
|
+
if (node.hint)
|
|
858
|
+
showMenuHint(event.currentTarget, node.hint);
|
|
859
|
+
if (hasChildren)
|
|
860
|
+
setMegaActiveId(node.id);
|
|
861
|
+
}, onMouseLeave: node.hint ? hideMenuHint : undefined, onClick: () => {
|
|
767
862
|
if (node.disabled)
|
|
768
863
|
return;
|
|
769
864
|
if (hasChildren) {
|
|
@@ -778,7 +873,12 @@ export function SgMenu(props) {
|
|
|
778
873
|
const hasChildren = !!node.children?.length;
|
|
779
874
|
const active = activeMegaNode?.id === node.id;
|
|
780
875
|
const iconNode = resolveIcon(node);
|
|
781
|
-
return (_jsxs("button", { type: "button", disabled: node.disabled, onMouseEnter: () =>
|
|
876
|
+
return (_jsxs("button", { type: "button", disabled: node.disabled, onMouseEnter: (event) => {
|
|
877
|
+
if (node.hint)
|
|
878
|
+
showMenuHint(event.currentTarget, node.hint);
|
|
879
|
+
if (hasChildren)
|
|
880
|
+
setMegaActiveId(node.id);
|
|
881
|
+
}, onMouseLeave: node.hint ? hideMenuHint : undefined, onClick: () => {
|
|
782
882
|
if (node.disabled)
|
|
783
883
|
return;
|
|
784
884
|
if (hasChildren) {
|
|
@@ -896,11 +996,18 @@ export function SgMenu(props) {
|
|
|
896
996
|
: undefined,
|
|
897
997
|
...style
|
|
898
998
|
}, children: [shellHeaderRow, !isCollapsed ? (_jsx("div", { className: cn("absolute z-50 flex flex-col bg-background text-foreground", effectiveMenuStyle === "tiered" ? "overflow-visible" : "overflow-auto", effectiveDockZone === "bottom" ? "bottom-full" : "top-full", horizontalDockAlign === "right" ? "right-0" : "left-0", "min-w-[240px]", effectiveMenuStyle !== "tiered" ? "max-h-[60vh]" : "", "border border-border", elevationClass(elevation === "none" ? "sm" : elevation)), children: shellContentArea })) : null] })) : (sidebarShell);
|
|
999
|
+
const menuHintNode = menuHint && typeof document !== "undefined"
|
|
1000
|
+
? createPortal(_jsx("span", { className: "pointer-events-none fixed z-[1200] max-w-[min(28rem,calc(100vw-24px))] rounded bg-foreground/90 px-2 py-1 text-[11px] text-background shadow-md whitespace-normal break-words", style: {
|
|
1001
|
+
left: menuHint.x,
|
|
1002
|
+
top: menuHint.y,
|
|
1003
|
+
transform: menuHint.placement === "right" ? "translateY(-50%)" : "translate(-50%, -100%)"
|
|
1004
|
+
}, children: menuHint.text }), document.body)
|
|
1005
|
+
: null;
|
|
899
1006
|
if (dockMode && portalTarget) {
|
|
900
|
-
return createPortal(shellForRender, portalTarget);
|
|
1007
|
+
return (_jsxs(_Fragment, { children: [createPortal(shellForRender, portalTarget), menuHintNode] }));
|
|
901
1008
|
}
|
|
902
1009
|
if (variant === "drawer") {
|
|
903
|
-
return (_jsx(SgExpandablePanel, { mode: "overlay", open: drawerOpen, onOpenChange: setDrawerOpen, expandTo: resolvedPosition === "left" ? "right" : "left", placement: "start", size: resolvedOverlaySize, animation: { type: "slide", durationMs: 180 }, border: border, elevation: elevation === "md" ? "lg" : elevation, rounded: "none", closeOnOutsideClick: !pinnedState, closeOnEsc: !pinnedState, trapFocus: true, showBackdrop: overlayBackdropResolved, ariaLabel: ariaLabel, role: "dialog", className: className, style: style, children: shellBody }));
|
|
1010
|
+
return (_jsxs(_Fragment, { children: [_jsx(SgExpandablePanel, { mode: "overlay", open: drawerOpen, onOpenChange: setDrawerOpen, expandTo: resolvedPosition === "left" ? "right" : "left", placement: "start", size: resolvedOverlaySize, animation: { type: "slide", durationMs: 180 }, border: border, elevation: elevation === "md" ? "lg" : elevation, rounded: "none", closeOnOutsideClick: !pinnedState, closeOnEsc: !pinnedState, trapFocus: true, showBackdrop: overlayBackdropResolved, ariaLabel: ariaLabel, role: "dialog", className: className, style: style, children: shellBody }), menuHintNode] }));
|
|
904
1011
|
}
|
|
905
1012
|
if (variant === "hybrid") {
|
|
906
1013
|
return (_jsxs(_Fragment, { children: [shellForRender, !pinnedState ? (_jsx(SgExpandablePanel, { mode: "overlay", open: drawerOpen, onOpenChange: setDrawerOpen, expandTo: resolvedPosition === "left" ? "right" : "left", placement: "start", size: resolvedOverlaySize, animation: { type: "slide", durationMs: 180 }, border: border, elevation: elevation === "md" ? "lg" : elevation, rounded: "none", closeOnOutsideClick: true, closeOnEsc: true, trapFocus: true, showBackdrop: overlayBackdropResolved, ariaLabel: ariaLabel, role: "dialog", children: _jsx(SgMenu, { menu: menu, selection: { activeId: effectiveActiveId, activeUrl: effectiveActiveUrl }, brand: brand, user: user, userMenu: userMenu, variant: "inline", menuStyle: menuStyle, position: position, density: density, indent: indent, collapsed: false, collapsedWidth: collapsedWidth, expandedWidth: expandedWidth, mode: mode, expandedIds: expandedIds, onExpandedIdsChange: setExpandedIds, showCollapseButton: false, showPinButton: showPinButton, pinned: pinnedState, onPinnedChange: (next) => {
|
|
@@ -918,9 +1025,9 @@ export function SgMenu(props) {
|
|
|
918
1025
|
}, onAction: onAction, onItemClick: (node) => {
|
|
919
1026
|
setLocalActiveId(node.id);
|
|
920
1027
|
onItemClick?.(node);
|
|
921
|
-
}, ariaLabel: ariaLabel, keyboardNavigation: keyboardNavigation, openSubmenuOnHover: openSubmenuOnHover, search: search, elevation: "none", border: false, footer: footer }) })) : null] }));
|
|
1028
|
+
}, ariaLabel: ariaLabel, keyboardNavigation: keyboardNavigation, openSubmenuOnHover: openSubmenuOnHover, search: search, elevation: "none", border: false, footer: footer }) })) : null, menuHintNode] }));
|
|
922
1029
|
}
|
|
923
|
-
return shellForRender;
|
|
1030
|
+
return (_jsxs(_Fragment, { children: [shellForRender, menuHintNode] }));
|
|
924
1031
|
}
|
|
925
1032
|
SgMenu.displayName = "SgMenu";
|
|
926
1033
|
function CollapseIcon(props) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SgPageControl.d.ts","sourceRoot":"","sources":["../../src/layout/SgPageControl.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAE1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,CACrB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,sBAAsB,CAAA;KAAE,KACrD,IAAI,CAAC;IACV,mBAAmB,CAAC,EAAE,CACpB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,sBAAsB,CAAA;KAAE,KACtD,IAAI,CAAC;IAEV,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;IAChC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAE/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B,CAAC;AAiCF,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,kBAAkB,CAAC,
|
|
1
|
+
{"version":3,"file":"SgPageControl.d.ts","sourceRoot":"","sources":["../../src/layout/SgPageControl.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAE1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,CACrB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,sBAAsB,CAAA;KAAE,KACrD,IAAI,CAAC;IACV,mBAAmB,CAAC,EAAE,CACpB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,sBAAsB,CAAA;KAAE,KACtD,IAAI,CAAC;IAEV,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IAEzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;IAChC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAE/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B,CAAC;AAiCF,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,kBAAkB,CAAC,2CAiQhE;yBAjQe,aAAa;;;AAqQ7B,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,sBAAsB,CAAC,2CAExE;yBAFe,iBAAiB"}
|
|
@@ -137,7 +137,7 @@ export function SgPageControl(props) {
|
|
|
137
137
|
const panelId = `${rootId}-panel-${record.id}`;
|
|
138
138
|
return (_jsxs("button", { ref: (el) => {
|
|
139
139
|
tabsRef.current[index] = el;
|
|
140
|
-
}, type: "button", id: tabId, role: "tab", "aria-controls": panelId, "aria-selected": isActive, tabIndex: isActive ? 0 : -1, disabled: record.props.disabled, onClick: () => selectPage(record.id), className: cn("inline-flex shrink-0 items-center justify-center whitespace-nowrap font-medium transition-colors", sizeClasses.tab, tabStyle.base, isActive ? tabStyle.active : tabStyle.inactive, fullWidthTabs ? "w-full" : "", record.props.disabled ? "cursor-not-allowed opacity-45" : "", tabClassName, record.props.tabClassName), children: [record.props.icon ? (_jsx("span", { className: cn("inline-flex items-center justify-center", sizeClasses.icon), children: record.props.icon })) : null, _jsx("span", { className: "truncate", children: record.props.title })] }, record.id));
|
|
140
|
+
}, type: "button", id: tabId, role: "tab", "aria-controls": panelId, "aria-selected": isActive, tabIndex: isActive ? 0 : -1, title: record.props.hint, disabled: record.props.disabled, onClick: () => selectPage(record.id), className: cn("inline-flex shrink-0 items-center justify-center whitespace-nowrap font-medium transition-colors", sizeClasses.tab, tabStyle.base, isActive ? tabStyle.active : tabStyle.inactive, fullWidthTabs ? "w-full" : "", record.props.disabled ? "cursor-not-allowed opacity-45" : "", tabClassName, record.props.tabClassName), children: [record.props.icon ? (_jsx("span", { className: cn("inline-flex items-center justify-center", sizeClasses.icon), children: record.props.icon })) : null, _jsx("span", { className: "truncate", children: record.props.title })] }, record.id));
|
|
141
141
|
}) }), _jsx("div", { className: cn("rounded-b-md border border-t-0 border-border bg-background", panelClassName), children: visiblePages.length === 0 ? (_jsx("div", { className: cn(sizeClasses.panel, "text-sm text-muted-foreground"), children: emptyMessage })) : keepMounted ? (visiblePages.map((record) => {
|
|
142
142
|
const isActive = record.id === resolvedActiveId;
|
|
143
143
|
const tabId = `${rootId}-tab-${record.id}`;
|
|
@@ -2,6 +2,7 @@ export type SgPlaygroundProps = {
|
|
|
2
2
|
code: string;
|
|
3
3
|
interactive?: boolean;
|
|
4
4
|
codeContract?: "renderBody" | "appFile";
|
|
5
|
+
preset?: SgPlaygroundPreset;
|
|
5
6
|
title?: string;
|
|
6
7
|
description?: string;
|
|
7
8
|
height?: number | string;
|
|
@@ -15,10 +16,21 @@ export type SgPlaygroundProps = {
|
|
|
15
16
|
defaultImports?: string;
|
|
16
17
|
previewWrapperClassName?: string;
|
|
17
18
|
seedgridDependency?: string;
|
|
19
|
+
bundlerURL?: string;
|
|
20
|
+
bundlerTimeoutMs?: number;
|
|
21
|
+
npmRegistries?: SgPlaygroundNpmRegistry[];
|
|
18
22
|
withCard?: boolean;
|
|
19
23
|
collapsible?: boolean;
|
|
20
24
|
defaultOpen?: boolean;
|
|
21
25
|
cardId?: string;
|
|
22
26
|
};
|
|
27
|
+
export type SgPlaygroundPreset = "auto" | "basic" | "seedgrid" | "editor" | "full";
|
|
28
|
+
export type SgPlaygroundNpmRegistry = {
|
|
29
|
+
enabledScopes: string[];
|
|
30
|
+
limitToScopes: boolean;
|
|
31
|
+
registryUrl: string;
|
|
32
|
+
proxyEnabled: boolean;
|
|
33
|
+
registryAuthToken?: string;
|
|
34
|
+
};
|
|
23
35
|
export default function SgPlayground(props: Readonly<SgPlaygroundProps>): import("react/jsx-runtime").JSX.Element;
|
|
24
36
|
//# sourceMappingURL=SgPlayground.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SgPlayground.d.ts","sourceRoot":"","sources":["../../src/others/SgPlayground.tsx"],"names":[],"mappings":"AAiBA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;IAChD,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;
|
|
1
|
+
{"version":3,"file":"SgPlayground.d.ts","sourceRoot":"","sources":["../../src/others/SgPlayground.tsx"],"names":[],"mappings":"AAiBA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACxC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;IAChD,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,uBAAuB,EAAE,CAAC;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;AACnF,MAAM,MAAM,uBAAuB,GAAG;IACpC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AA0vBF,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,iBAAiB,CAAC,2CAsZtE"}
|
|
@@ -7,12 +7,21 @@ import { SgCard } from "../layout/SgCard";
|
|
|
7
7
|
function cn(...parts) {
|
|
8
8
|
return parts.filter(Boolean).join(" ");
|
|
9
9
|
}
|
|
10
|
-
const DEFAULT_SEEDGRID_DEPENDENCY = "
|
|
11
|
-
const
|
|
12
|
-
|
|
10
|
+
const DEFAULT_SEEDGRID_DEPENDENCY = "latest";
|
|
11
|
+
const DEFAULT_SANDPACK_BUNDLER_URL = "https://sandpack.seedgrid.com.br";
|
|
12
|
+
const DEFAULT_SANDPACK_BUNDLER_TIMEOUT_MS = 60000;
|
|
13
|
+
const DEFAULT_SANDBOX_BASE_DEPENDENCIES = {
|
|
14
|
+
react: "18.2.0",
|
|
15
|
+
"react-dom": "18.2.0"
|
|
16
|
+
};
|
|
17
|
+
const DEFAULT_SEEDGRID_RUNTIME_DEPENDENCIES = {
|
|
13
18
|
"react-hook-form": "^7.0.0",
|
|
14
|
-
"lucide-react": "^0.468.0"
|
|
19
|
+
"lucide-react": "^0.468.0"
|
|
20
|
+
};
|
|
21
|
+
const DEFAULT_SEEDGRID_EDITOR_DEPENDENCIES = {
|
|
22
|
+
"@tiptap/core": "^2.9.1",
|
|
15
23
|
"@tiptap/react": "^2.9.1",
|
|
24
|
+
"@tiptap/pm": "^2.9.1",
|
|
16
25
|
"@tiptap/starter-kit": "^2.9.1",
|
|
17
26
|
"@tiptap/extension-underline": "^2.9.1",
|
|
18
27
|
"@tiptap/extension-link": "^2.9.1",
|
|
@@ -25,10 +34,255 @@ const DEFAULT_SEEDGRID_PEER_DEPENDENCIES = {
|
|
|
25
34
|
"@tiptap/extension-superscript": "^2.9.1",
|
|
26
35
|
"@tiptap/extension-font-family": "^2.9.1"
|
|
27
36
|
};
|
|
37
|
+
const DEFAULT_SANDBOX_HOST_DEPENDENCIES = {
|
|
38
|
+
"@codesandbox/sandpack-react": "^2.20.0"
|
|
39
|
+
};
|
|
40
|
+
const DEFAULT_SANDPACK_POLYFILLS = {
|
|
41
|
+
assert: "^2.1.0",
|
|
42
|
+
process: "^0.11.10",
|
|
43
|
+
util: "^0.12.5"
|
|
44
|
+
};
|
|
45
|
+
const TIPTAP_SHIM_PACKAGES = [
|
|
46
|
+
"@tiptap/core",
|
|
47
|
+
"@tiptap/pm",
|
|
48
|
+
"@tiptap/starter-kit",
|
|
49
|
+
"@tiptap/extension-underline",
|
|
50
|
+
"@tiptap/extension-link",
|
|
51
|
+
"@tiptap/extension-image",
|
|
52
|
+
"@tiptap/extension-text-align",
|
|
53
|
+
"@tiptap/extension-text-style",
|
|
54
|
+
"@tiptap/extension-color",
|
|
55
|
+
"@tiptap/extension-highlight",
|
|
56
|
+
"@tiptap/extension-subscript",
|
|
57
|
+
"@tiptap/extension-superscript",
|
|
58
|
+
"@tiptap/extension-font-family"
|
|
59
|
+
];
|
|
28
60
|
const SANDPACK_EXTERNAL_RESOURCES = [
|
|
29
61
|
// Prebuilt utility CSS so classes from @seedgrid/fe-components can render inside Sandpack
|
|
30
62
|
"https://unpkg.com/tailwindcss@2.2.19/dist/tailwind.min.css"
|
|
31
63
|
];
|
|
64
|
+
const SANDPACK_QRCODE_SHIM_INDEX_JS = `const makeError = () =>
|
|
65
|
+
new Error(
|
|
66
|
+
"qrcode (node build) is not supported in Sandpack browser runtime. Update @seedgrid/fe-components to a browser-safe QR implementation."
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const qrcodeShim = {
|
|
70
|
+
toDataURL() {
|
|
71
|
+
return Promise.reject(makeError());
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const toDataURL = (...args) => qrcodeShim.toDataURL(...args);
|
|
76
|
+
export default qrcodeShim;
|
|
77
|
+
`;
|
|
78
|
+
const SANDPACK_MARKDOWN_IT_BIN_SHIM = `import markdownit from "../index.mjs";
|
|
79
|
+
|
|
80
|
+
// Browser-safe shim: Sandpack must not execute markdown-it CLI entrypoint.
|
|
81
|
+
// Re-export parser factory so accidental imports of the bin path remain harmless.
|
|
82
|
+
export default markdownit;
|
|
83
|
+
export { markdownit };
|
|
84
|
+
`;
|
|
85
|
+
const SANDPACK_SANDBOX_SANDPACK_REACT_SHIM_INDEX_JS = `export const SandpackProvider = ({ children }) => children ?? null;
|
|
86
|
+
export const SandpackCodeEditor = () => null;
|
|
87
|
+
export const SandpackPreview = () => null;
|
|
88
|
+
export const useSandpack = () => ({
|
|
89
|
+
sandpack: {
|
|
90
|
+
activeFile: "/App.tsx",
|
|
91
|
+
files: { "/App.tsx": { code: "" } },
|
|
92
|
+
runSandpack: async () => {},
|
|
93
|
+
clients: {},
|
|
94
|
+
status: "idle"
|
|
95
|
+
},
|
|
96
|
+
dispatch: () => {},
|
|
97
|
+
listen: () => () => {}
|
|
98
|
+
});
|
|
99
|
+
export default {};
|
|
100
|
+
`;
|
|
101
|
+
const SANDPACK_TIPTAP_REACT_SHIM_INDEX_JS = `export const EditorContent = () => null;
|
|
102
|
+
export const BubbleMenu = () => null;
|
|
103
|
+
export const FloatingMenu = () => null;
|
|
104
|
+
export const useEditor = () => null;
|
|
105
|
+
export default {};
|
|
106
|
+
`;
|
|
107
|
+
const SANDPACK_TIPTAP_EXTENSION_SHIM_INDEX_JS = `const extension = {
|
|
108
|
+
configure() {
|
|
109
|
+
return extension;
|
|
110
|
+
},
|
|
111
|
+
extend() {
|
|
112
|
+
return extension;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
export default extension;
|
|
116
|
+
`;
|
|
117
|
+
const SANDPACK_SEEDGRID_TEXT_EDITOR_SHIM_INDEX_JS = `import * as React from "react";
|
|
118
|
+
|
|
119
|
+
export function SgTextEditor() {
|
|
120
|
+
return React.createElement(
|
|
121
|
+
"div",
|
|
122
|
+
{
|
|
123
|
+
style: {
|
|
124
|
+
padding: "0.75rem",
|
|
125
|
+
border: "1px solid #e4e4e7",
|
|
126
|
+
borderRadius: "0.5rem",
|
|
127
|
+
fontSize: "0.875rem",
|
|
128
|
+
color: "#6b7280",
|
|
129
|
+
background: "#f9fafb"
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"SgTextEditor is disabled in this sandbox preset."
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export default SgTextEditor;
|
|
137
|
+
`;
|
|
138
|
+
const SANDPACK_ASSERT_SHIM_INDEX_JS = `function fail(message) {
|
|
139
|
+
throw new Error(message || "Assertion failed");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function assert(value, message) {
|
|
143
|
+
if (!value) fail(message);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
assert.ok = assert;
|
|
147
|
+
assert.equal = function equal(actual, expected, message) {
|
|
148
|
+
if (actual != expected) fail(message || "Expected values to be loosely equal");
|
|
149
|
+
};
|
|
150
|
+
assert.strictEqual = function strictEqual(actual, expected, message) {
|
|
151
|
+
if (actual !== expected) fail(message || "Expected values to be strictly equal");
|
|
152
|
+
};
|
|
153
|
+
assert.notEqual = function notEqual(actual, expected, message) {
|
|
154
|
+
if (actual == expected) fail(message || "Expected values to be different");
|
|
155
|
+
};
|
|
156
|
+
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
|
|
157
|
+
if (actual === expected) fail(message || "Expected values to be different");
|
|
158
|
+
};
|
|
159
|
+
assert.deepEqual = function deepEqual(actual, expected, message) {
|
|
160
|
+
try {
|
|
161
|
+
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
|
|
162
|
+
fail(message || "Expected values to be deeply equal");
|
|
163
|
+
}
|
|
164
|
+
} catch (_) {
|
|
165
|
+
if (actual !== expected) fail(message || "Expected values to be deeply equal");
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
assert.throws = function throwsAssertion(fn, message) {
|
|
169
|
+
var didThrow = false;
|
|
170
|
+
try { fn(); } catch (_) { didThrow = true; }
|
|
171
|
+
if (!didThrow) fail(message || "Expected function to throw");
|
|
172
|
+
};
|
|
173
|
+
assert.fail = fail;
|
|
174
|
+
|
|
175
|
+
module.exports = assert;
|
|
176
|
+
module.exports.default = assert;
|
|
177
|
+
`;
|
|
178
|
+
const SANDPACK_UTIL_SHIM_INDEX_JS = `const inspect = function inspect(value) {
|
|
179
|
+
try {
|
|
180
|
+
return JSON.stringify(value);
|
|
181
|
+
} catch (_) {
|
|
182
|
+
return String(value);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
inspect.custom = typeof Symbol !== "undefined" && Symbol.for
|
|
187
|
+
? Symbol.for("nodejs.util.inspect.custom")
|
|
188
|
+
: "@@nodejs.util.inspect.custom";
|
|
189
|
+
|
|
190
|
+
function deprecate(fn, message) {
|
|
191
|
+
var warned = false;
|
|
192
|
+
return function deprecatedWrapper() {
|
|
193
|
+
if (!warned && typeof console !== "undefined" && typeof console.warn === "function") {
|
|
194
|
+
console.warn(message);
|
|
195
|
+
warned = true;
|
|
196
|
+
}
|
|
197
|
+
return fn.apply(this, arguments);
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function format() {
|
|
202
|
+
return Array.prototype.map.call(arguments, function (item) {
|
|
203
|
+
return String(item);
|
|
204
|
+
}).join(" ");
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const utilShim = { inspect, deprecate, format };
|
|
208
|
+
module.exports = utilShim;
|
|
209
|
+
module.exports.default = utilShim;
|
|
210
|
+
`;
|
|
211
|
+
const SANDPACK_PATH_SHIM_INDEX_JS = `function normalize(input) {
|
|
212
|
+
return String(input || "").replace(/\\\\/g, "/");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function basename(input) {
|
|
216
|
+
var text = normalize(input);
|
|
217
|
+
var pieces = text.split("/").filter(Boolean);
|
|
218
|
+
return pieces.length ? pieces[pieces.length - 1] : "";
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function dirname(input) {
|
|
222
|
+
var text = normalize(input);
|
|
223
|
+
var index = text.lastIndexOf("/");
|
|
224
|
+
if (index <= 0) return ".";
|
|
225
|
+
return text.slice(0, index);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function join() {
|
|
229
|
+
return Array.prototype
|
|
230
|
+
.map.call(arguments, normalize)
|
|
231
|
+
.filter(Boolean)
|
|
232
|
+
.join("/")
|
|
233
|
+
.replace(/\\/{2,}/g, "/");
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function resolve() {
|
|
237
|
+
return join.apply(null, arguments);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const pathShim = {
|
|
241
|
+
sep: "/",
|
|
242
|
+
delimiter: ":",
|
|
243
|
+
basename,
|
|
244
|
+
dirname,
|
|
245
|
+
join,
|
|
246
|
+
resolve,
|
|
247
|
+
normalize
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
module.exports = pathShim;
|
|
251
|
+
module.exports.default = pathShim;
|
|
252
|
+
`;
|
|
253
|
+
const SANDPACK_FS_SHIM_INDEX_JS = `function notSupported(name) {
|
|
254
|
+
throw new Error("fs." + name + " is not supported in Sandpack browser runtime.");
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const fsShim = {
|
|
258
|
+
openSync: function openSync() { return notSupported("openSync"); },
|
|
259
|
+
createReadStream: function createReadStream() { return notSupported("createReadStream"); },
|
|
260
|
+
createWriteStream: function createWriteStream() { return notSupported("createWriteStream"); },
|
|
261
|
+
readFileSync: function readFileSync() { return notSupported("readFileSync"); }
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
module.exports = fsShim;
|
|
265
|
+
module.exports.default = fsShim;
|
|
266
|
+
`;
|
|
267
|
+
const SANDPACK_PROCESS_SHIM_INDEX_JS = `const processShim = {
|
|
268
|
+
env: {},
|
|
269
|
+
argv: ["browser"],
|
|
270
|
+
stdout: { columns: 80 },
|
|
271
|
+
stderr: { columns: 80 },
|
|
272
|
+
cwd: function cwd() { return "/"; },
|
|
273
|
+
nextTick: function nextTick(fn) {
|
|
274
|
+
var args = Array.prototype.slice.call(arguments, 1);
|
|
275
|
+
return Promise.resolve().then(function () { return fn.apply(null, args); });
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
if (typeof globalThis !== "undefined" && !globalThis.process) {
|
|
280
|
+
globalThis.process = processShim;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
module.exports = processShim;
|
|
284
|
+
module.exports.default = processShim;
|
|
285
|
+
`;
|
|
32
286
|
const SANDPACK_FALLBACK_THEME_VARS = {
|
|
33
287
|
"--background": "0 0% 100%",
|
|
34
288
|
"--foreground": "222.2 84% 4.9%",
|
|
@@ -103,6 +357,100 @@ body {
|
|
|
103
357
|
.size-4 { width: 1rem; height: 1rem; }
|
|
104
358
|
.size-5 { width: 1.25rem; height: 1.25rem; }
|
|
105
359
|
`;
|
|
360
|
+
const SANDPACK_HOST_STYLES_CSS = `
|
|
361
|
+
.sg-playground-preview .sp-cube-wrapper {
|
|
362
|
+
top: 8px !important;
|
|
363
|
+
right: 8px !important;
|
|
364
|
+
bottom: auto !important;
|
|
365
|
+
left: auto !important;
|
|
366
|
+
}
|
|
367
|
+
`;
|
|
368
|
+
function normalizeUrl(raw, fallback) {
|
|
369
|
+
const value = raw?.trim();
|
|
370
|
+
if (!value)
|
|
371
|
+
return fallback;
|
|
372
|
+
try {
|
|
373
|
+
const parsed = new URL(value);
|
|
374
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
return fallback;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
function normalizeTimeoutMs(value, fallback) {
|
|
381
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
382
|
+
return fallback;
|
|
383
|
+
}
|
|
384
|
+
return Math.round(value);
|
|
385
|
+
}
|
|
386
|
+
function parseBooleanFlag(value, fallback) {
|
|
387
|
+
const normalized = value?.trim().toLowerCase();
|
|
388
|
+
if (!normalized)
|
|
389
|
+
return fallback;
|
|
390
|
+
if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
return fallback;
|
|
397
|
+
}
|
|
398
|
+
function resolveDefaultNpmRegistriesFromEnv() {
|
|
399
|
+
const registryUrlRaw = process.env.NEXT_PUBLIC_SANDPACK_NPM_REGISTRY_URL?.trim();
|
|
400
|
+
if (!registryUrlRaw)
|
|
401
|
+
return undefined;
|
|
402
|
+
const scopesRaw = process.env.NEXT_PUBLIC_SANDPACK_NPM_REGISTRY_SCOPES;
|
|
403
|
+
const enabledScopes = (scopesRaw ?? "@seedgrid")
|
|
404
|
+
.split(",")
|
|
405
|
+
.map((scope) => scope.trim())
|
|
406
|
+
.filter(Boolean);
|
|
407
|
+
const limitToScopes = parseBooleanFlag(process.env.NEXT_PUBLIC_SANDPACK_NPM_REGISTRY_LIMIT_TO_SCOPES, true);
|
|
408
|
+
const proxyEnabled = parseBooleanFlag(process.env.NEXT_PUBLIC_SANDPACK_NPM_REGISTRY_PROXY_ENABLED, false);
|
|
409
|
+
const registryAuthToken = process.env.NEXT_PUBLIC_SANDPACK_NPM_REGISTRY_AUTH_TOKEN?.trim();
|
|
410
|
+
return [
|
|
411
|
+
{
|
|
412
|
+
enabledScopes,
|
|
413
|
+
limitToScopes,
|
|
414
|
+
registryUrl: registryUrlRaw.replace(/\/+$/, ""),
|
|
415
|
+
proxyEnabled,
|
|
416
|
+
...(registryAuthToken ? { registryAuthToken } : {})
|
|
417
|
+
}
|
|
418
|
+
];
|
|
419
|
+
}
|
|
420
|
+
function buildCjsModule(value) {
|
|
421
|
+
const serialized = JSON.stringify(value);
|
|
422
|
+
return `const data = ${serialized};
|
|
423
|
+
module.exports = data;
|
|
424
|
+
module.exports.default = data;
|
|
425
|
+
`;
|
|
426
|
+
}
|
|
427
|
+
const SANDPACK_MIN_COMPONENT_MESSAGES = {
|
|
428
|
+
"components.actions.clear": "Clear",
|
|
429
|
+
"components.actions.cancel": "Cancel",
|
|
430
|
+
"components.actions.confirm": "Confirm",
|
|
431
|
+
"components.inputs.required": "Required field.",
|
|
432
|
+
"components.inputs.maxLength": "Maximum {max} characters.",
|
|
433
|
+
"components.inputs.minLength": "Minimum {min} characters.",
|
|
434
|
+
"components.inputs.minWords": "Minimum {min} words.",
|
|
435
|
+
"components.inputs.email.invalid": "Invalid email.",
|
|
436
|
+
"components.inputs.phone.invalid": "Invalid phone.",
|
|
437
|
+
"components.inputs.date.invalid": "Invalid date.",
|
|
438
|
+
"components.inputs.number.min": "Value must be at least {min}.",
|
|
439
|
+
"components.inputs.number.max": "Value must be at most {max}.",
|
|
440
|
+
"components.password.show": "Show password",
|
|
441
|
+
"components.password.hide": "Hide password",
|
|
442
|
+
"components.autocomplete.empty": "No records found.",
|
|
443
|
+
"components.autocomplete.loading": "Loading...",
|
|
444
|
+
"components.rating.cancel": "Cancel rating",
|
|
445
|
+
"components.radiogroup.cancel": "No option"
|
|
446
|
+
};
|
|
447
|
+
const SANDPACK_SEEDGRID_PT_BR_JSON_SHIM = buildCjsModule(SANDPACK_MIN_COMPONENT_MESSAGES);
|
|
448
|
+
const SANDPACK_SEEDGRID_PT_PT_JSON_SHIM = buildCjsModule(SANDPACK_MIN_COMPONENT_MESSAGES);
|
|
449
|
+
const SANDPACK_SEEDGRID_EN_US_JSON_SHIM = buildCjsModule(SANDPACK_MIN_COMPONENT_MESSAGES);
|
|
450
|
+
const SANDPACK_SEEDGRID_ES_JSON_SHIM = buildCjsModule(SANDPACK_MIN_COMPONENT_MESSAGES);
|
|
451
|
+
const SANDPACK_SEEDGRID_BLOCKED_EMAIL_DOMAINS_JSON_SHIM = buildCjsModule({
|
|
452
|
+
blockedEmailDomains: []
|
|
453
|
+
});
|
|
106
454
|
function parseRgbParts(raw) {
|
|
107
455
|
const value = raw.trim();
|
|
108
456
|
if (!value)
|
|
@@ -303,13 +651,45 @@ function CopyButton() {
|
|
|
303
651
|
}
|
|
304
652
|
function RunButton({ onRun }) {
|
|
305
653
|
const { sandpack } = useSandpack();
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
654
|
+
const [running, setRunning] = React.useState(false);
|
|
655
|
+
const handleRun = React.useCallback(async () => {
|
|
656
|
+
if (running)
|
|
657
|
+
return;
|
|
658
|
+
setRunning(true);
|
|
659
|
+
onRun?.();
|
|
660
|
+
try {
|
|
661
|
+
if (typeof window !== "undefined") {
|
|
662
|
+
await new Promise((resolve) => {
|
|
663
|
+
window.requestAnimationFrame(() => window.requestAnimationFrame(() => resolve()));
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
// On lazy init + hidden preview scenarios, iframe/client registration can lag by a tick.
|
|
667
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
668
|
+
await sandpack.runSandpack();
|
|
669
|
+
if (sandpack.status === "running" ||
|
|
670
|
+
sandpack.status === "done" ||
|
|
671
|
+
Object.keys(sandpack.clients ?? {}).length > 0) {
|
|
672
|
+
break;
|
|
673
|
+
}
|
|
674
|
+
await new Promise((resolve) => setTimeout(resolve, 120));
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
catch (error) {
|
|
678
|
+
console.error("[SgPlayground] Failed to run Sandpack", error);
|
|
679
|
+
}
|
|
680
|
+
finally {
|
|
681
|
+
if (typeof window !== "undefined") {
|
|
682
|
+
window.setTimeout(() => setRunning(false), 150);
|
|
683
|
+
}
|
|
684
|
+
else {
|
|
685
|
+
setRunning(false);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}, [onRun, running, sandpack]);
|
|
689
|
+
return (_jsx(SgButton, { severity: "primary", size: "sm", loading: running, onClick: handleRun, children: running ? "Running" : "Run" }));
|
|
310
690
|
}
|
|
311
691
|
export default function SgPlayground(props) {
|
|
312
|
-
const { code, interactive = false, codeContract = "renderBody", title, description, height = 360, expandedHeight = "70vh", expandable = true, resizable = true, resizeAxis = "vertical", previewPadding, className, dependencies, defaultImports, previewWrapperClassName = "h-[420px] rounded-xl border border-border bg-muted/30 p-3", seedgridDependency, withCard = true, collapsible = true, defaultOpen = true, cardId } = props;
|
|
692
|
+
const { code, interactive = false, codeContract = "renderBody", preset = "auto", title, description, height = 360, expandedHeight = "70vh", expandable = true, resizable = true, resizeAxis = "vertical", previewPadding, className, dependencies, defaultImports, previewWrapperClassName = "h-[420px] rounded-xl border border-border bg-muted/30 p-3", seedgridDependency, bundlerURL, bundlerTimeoutMs, npmRegistries, withCard = true, collapsible = true, defaultOpen = true, cardId } = props;
|
|
313
693
|
const effectivePreviewPadding = normalizeCssSize(previewPadding ?? (codeContract === "appFile" ? 12 : 0));
|
|
314
694
|
const [sandpackStylesCss, setSandpackStylesCss] = React.useState(() => buildSandpackStylesCss({}, effectivePreviewPadding));
|
|
315
695
|
const [isExpanded, setIsExpanded] = React.useState(false);
|
|
@@ -359,16 +739,149 @@ export default function SgPlayground(props) {
|
|
|
359
739
|
const resolvedSeedgridDependency = seedgridDependency ??
|
|
360
740
|
process.env.NEXT_PUBLIC_SANDPACK_SEEDGRID_DEPENDENCY ??
|
|
361
741
|
DEFAULT_SEEDGRID_DEPENDENCY;
|
|
742
|
+
const requestedDeps = dependencies ?? {};
|
|
743
|
+
const requestedDepKeys = Object.keys(requestedDeps);
|
|
744
|
+
const resolvedBundlerURL = normalizeUrl(bundlerURL ?? process.env.NEXT_PUBLIC_SANDPACK_BUNDLER_URL, DEFAULT_SANDPACK_BUNDLER_URL);
|
|
745
|
+
const resolvedBundlerTimeoutMs = normalizeTimeoutMs(bundlerTimeoutMs ??
|
|
746
|
+
Number(process.env.NEXT_PUBLIC_SANDPACK_BUNDLER_TIMEOUT_MS ?? Number.NaN), DEFAULT_SANDPACK_BUNDLER_TIMEOUT_MS);
|
|
747
|
+
const resolvedNpmRegistries = React.useMemo(() => npmRegistries ?? resolveDefaultNpmRegistriesFromEnv(), [npmRegistries]);
|
|
748
|
+
React.useEffect(() => {
|
|
749
|
+
if (!interactive)
|
|
750
|
+
return;
|
|
751
|
+
if (!parseBooleanFlag(process.env.NEXT_PUBLIC_SANDPACK_DEBUG, false))
|
|
752
|
+
return;
|
|
753
|
+
console.info("[SgPlayground] Sandpack runtime config", {
|
|
754
|
+
bundlerURL: resolvedBundlerURL,
|
|
755
|
+
bundlerTimeoutMs: resolvedBundlerTimeoutMs,
|
|
756
|
+
npmRegistries: (resolvedNpmRegistries ?? []).map((registry) => ({
|
|
757
|
+
enabledScopes: registry.enabledScopes,
|
|
758
|
+
limitToScopes: registry.limitToScopes,
|
|
759
|
+
registryUrl: registry.registryUrl,
|
|
760
|
+
proxyEnabled: registry.proxyEnabled
|
|
761
|
+
}))
|
|
762
|
+
});
|
|
763
|
+
}, [interactive, resolvedBundlerTimeoutMs, resolvedBundlerURL, resolvedNpmRegistries]);
|
|
764
|
+
const codeUsesSeedgrid = /from\s+["']@seedgrid\/fe-components["']/.test(appTsx);
|
|
765
|
+
const codeUsesTextEditor = /\bSgTextEditor\b/.test(appTsx);
|
|
766
|
+
const codeUsesPlaygroundComponent = /\bSgPlayground\b/.test(appTsx);
|
|
767
|
+
const resolvedPreset = preset === "auto"
|
|
768
|
+
? codeUsesTextEditor
|
|
769
|
+
? "editor"
|
|
770
|
+
: codeUsesSeedgrid
|
|
771
|
+
? "seedgrid"
|
|
772
|
+
: "basic"
|
|
773
|
+
: preset;
|
|
774
|
+
const includeSeedgridDependency = resolvedPreset === "seedgrid" ||
|
|
775
|
+
resolvedPreset === "editor" ||
|
|
776
|
+
resolvedPreset === "full" ||
|
|
777
|
+
requestedDepKeys.includes("@seedgrid/fe-components");
|
|
778
|
+
const includeEditorDependencies = resolvedPreset === "editor" ||
|
|
779
|
+
resolvedPreset === "full" ||
|
|
780
|
+
codeUsesTextEditor ||
|
|
781
|
+
requestedDepKeys.some((dep) => dep.startsWith("@tiptap/"));
|
|
782
|
+
const includeSandpackReactDependency = resolvedPreset === "full" ||
|
|
783
|
+
codeUsesPlaygroundComponent ||
|
|
784
|
+
requestedDepKeys.includes("@codesandbox/sandpack-react");
|
|
785
|
+
const shouldShimSandpackReact = includeSeedgridDependency && !includeSandpackReactDependency;
|
|
786
|
+
const shouldShimTiptap = includeSeedgridDependency && !includeEditorDependencies;
|
|
787
|
+
const shouldIncludeNodePolyfills = includeEditorDependencies;
|
|
362
788
|
const files = {
|
|
363
789
|
"/App.tsx": { code: appTsx, active: true },
|
|
364
790
|
"/styles.css": { code: sandpackStylesCss || buildSandpackStylesCss({}, effectivePreviewPadding) }
|
|
365
791
|
};
|
|
792
|
+
if (includeSeedgridDependency) {
|
|
793
|
+
// Compatibility shim for legacy @seedgrid/fe-components builds that still import "qrcode" (node-only path).
|
|
794
|
+
files["/node_modules/qrcode/index.js"] = { code: SANDPACK_QRCODE_SHIM_INDEX_JS, hidden: true };
|
|
795
|
+
// Sandpack runtime can evaluate JSON files as plain JS modules.
|
|
796
|
+
// Provide CJS-compatible shims to keep @seedgrid/fe-components i18n/validators working.
|
|
797
|
+
files["/node_modules/@seedgrid/fe-components/dist/i18n/pt-BR.json"] = {
|
|
798
|
+
code: SANDPACK_SEEDGRID_PT_BR_JSON_SHIM,
|
|
799
|
+
hidden: true
|
|
800
|
+
};
|
|
801
|
+
files["/node_modules/@seedgrid/fe-components/dist/i18n/pt-PT.json"] = {
|
|
802
|
+
code: SANDPACK_SEEDGRID_PT_PT_JSON_SHIM,
|
|
803
|
+
hidden: true
|
|
804
|
+
};
|
|
805
|
+
files["/node_modules/@seedgrid/fe-components/dist/i18n/en-US.json"] = {
|
|
806
|
+
code: SANDPACK_SEEDGRID_EN_US_JSON_SHIM,
|
|
807
|
+
hidden: true
|
|
808
|
+
};
|
|
809
|
+
files["/node_modules/@seedgrid/fe-components/dist/i18n/es.json"] = {
|
|
810
|
+
code: SANDPACK_SEEDGRID_ES_JSON_SHIM,
|
|
811
|
+
hidden: true
|
|
812
|
+
};
|
|
813
|
+
files["/node_modules/@seedgrid/fe-components/dist/blocked-email-domains.json"] = {
|
|
814
|
+
code: SANDPACK_SEEDGRID_BLOCKED_EMAIL_DOMAINS_JSON_SHIM,
|
|
815
|
+
hidden: true
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
if (shouldIncludeNodePolyfills) {
|
|
819
|
+
// markdown-it CLI entry uses node:fs and breaks in browser runtime.
|
|
820
|
+
files["/node_modules/markdown-it/bin/markdown-it.mjs"] = {
|
|
821
|
+
code: SANDPACK_MARKDOWN_IT_BIN_SHIM,
|
|
822
|
+
hidden: true
|
|
823
|
+
};
|
|
824
|
+
// Node builtin compatibility shims used by transitive dependencies (e.g. argparse from markdown-it/tiptap).
|
|
825
|
+
files["/node_modules/assert/index.js"] = { code: SANDPACK_ASSERT_SHIM_INDEX_JS, hidden: true };
|
|
826
|
+
files["/node_modules/util/index.js"] = { code: SANDPACK_UTIL_SHIM_INDEX_JS, hidden: true };
|
|
827
|
+
files["/node_modules/path/index.js"] = { code: SANDPACK_PATH_SHIM_INDEX_JS, hidden: true };
|
|
828
|
+
files["/node_modules/fs/index.js"] = { code: SANDPACK_FS_SHIM_INDEX_JS, hidden: true };
|
|
829
|
+
files["/node_modules/process/index.js"] = { code: SANDPACK_PROCESS_SHIM_INDEX_JS, hidden: true };
|
|
830
|
+
}
|
|
831
|
+
if (shouldShimSandpackReact) {
|
|
832
|
+
files["/node_modules/@codesandbox/sandpack-react/index.js"] = {
|
|
833
|
+
code: SANDPACK_SANDBOX_SANDPACK_REACT_SHIM_INDEX_JS,
|
|
834
|
+
hidden: true
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
if (shouldShimTiptap) {
|
|
838
|
+
files["/node_modules/@seedgrid/fe-components/dist/inputs/SgTextEditor.js"] = {
|
|
839
|
+
code: SANDPACK_SEEDGRID_TEXT_EDITOR_SHIM_INDEX_JS,
|
|
840
|
+
hidden: true
|
|
841
|
+
};
|
|
842
|
+
files["/node_modules/@seedgrid/fe-components/dist/inputs/SgTextEditor"] = {
|
|
843
|
+
code: SANDPACK_SEEDGRID_TEXT_EDITOR_SHIM_INDEX_JS,
|
|
844
|
+
hidden: true
|
|
845
|
+
};
|
|
846
|
+
files["/node_modules/@seedgrid/fe-components/dist/inputs/SgTextEditor.mjs"] = {
|
|
847
|
+
code: SANDPACK_SEEDGRID_TEXT_EDITOR_SHIM_INDEX_JS,
|
|
848
|
+
hidden: true
|
|
849
|
+
};
|
|
850
|
+
files["/node_modules/@tiptap/react/package.json"] = {
|
|
851
|
+
code: JSON.stringify({ name: "@tiptap/react", version: "0.0.0-shim", main: "index.js", module: "index.mjs" }),
|
|
852
|
+
hidden: true
|
|
853
|
+
};
|
|
854
|
+
files["/node_modules/@tiptap/react/index.js"] = {
|
|
855
|
+
code: SANDPACK_TIPTAP_REACT_SHIM_INDEX_JS,
|
|
856
|
+
hidden: true
|
|
857
|
+
};
|
|
858
|
+
files["/node_modules/@tiptap/react/index.mjs"] = {
|
|
859
|
+
code: SANDPACK_TIPTAP_REACT_SHIM_INDEX_JS,
|
|
860
|
+
hidden: true
|
|
861
|
+
};
|
|
862
|
+
for (const packageName of TIPTAP_SHIM_PACKAGES) {
|
|
863
|
+
files[`/node_modules/${packageName}/package.json`] = {
|
|
864
|
+
code: JSON.stringify({ name: packageName, version: "0.0.0-shim", main: "index.js", module: "index.mjs" }),
|
|
865
|
+
hidden: true
|
|
866
|
+
};
|
|
867
|
+
files[`/node_modules/${packageName}/index.js`] = {
|
|
868
|
+
code: SANDPACK_TIPTAP_EXTENSION_SHIM_INDEX_JS,
|
|
869
|
+
hidden: true
|
|
870
|
+
};
|
|
871
|
+
files[`/node_modules/${packageName}/index.mjs`] = {
|
|
872
|
+
code: SANDPACK_TIPTAP_EXTENSION_SHIM_INDEX_JS,
|
|
873
|
+
hidden: true
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
}
|
|
366
877
|
const deps = {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
...
|
|
370
|
-
|
|
371
|
-
...(
|
|
878
|
+
...DEFAULT_SANDBOX_BASE_DEPENDENCIES,
|
|
879
|
+
...(includeSeedgridDependency ? DEFAULT_SEEDGRID_RUNTIME_DEPENDENCIES : {}),
|
|
880
|
+
...(includeEditorDependencies ? DEFAULT_SEEDGRID_EDITOR_DEPENDENCIES : {}),
|
|
881
|
+
...(includeSandpackReactDependency ? DEFAULT_SANDBOX_HOST_DEPENDENCIES : {}),
|
|
882
|
+
...(shouldIncludeNodePolyfills ? DEFAULT_SANDPACK_POLYFILLS : {}),
|
|
883
|
+
...(includeSeedgridDependency ? { "@seedgrid/fe-components": resolvedSeedgridDependency } : {}),
|
|
884
|
+
...requestedDeps
|
|
372
885
|
};
|
|
373
886
|
const currentHeight = isExpanded ? expandedHeight : height;
|
|
374
887
|
const resizeClass = !resizable
|
|
@@ -378,18 +891,27 @@ export default function SgPlayground(props) {
|
|
|
378
891
|
: resizeAxis === "horizontal"
|
|
379
892
|
? "resize-x"
|
|
380
893
|
: "resize";
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
894
|
+
const sandpackCustomSetup = React.useMemo(() => ({
|
|
895
|
+
dependencies: deps,
|
|
896
|
+
entry: "/index.tsx",
|
|
897
|
+
...(resolvedNpmRegistries ? { npmRegistries: resolvedNpmRegistries } : {})
|
|
898
|
+
}), [deps, resolvedNpmRegistries]);
|
|
899
|
+
const sandpackOptions = React.useMemo(() => ({
|
|
900
|
+
autorun: false,
|
|
901
|
+
initMode: "lazy",
|
|
902
|
+
bundlerURL: resolvedBundlerURL,
|
|
903
|
+
// Keep both keys while sandpack typings/runtime differ across versions.
|
|
904
|
+
bundlerTimeOut: resolvedBundlerTimeoutMs,
|
|
905
|
+
bundlerTimeout: resolvedBundlerTimeoutMs,
|
|
906
|
+
activeFile: "/App.tsx",
|
|
907
|
+
visibleFiles: ["/App.tsx"],
|
|
908
|
+
externalResources: SANDPACK_EXTERNAL_RESOURCES
|
|
909
|
+
}), [resolvedBundlerTimeoutMs, resolvedBundlerURL]);
|
|
910
|
+
const content = interactive ? (_jsx("div", { className: cn(withCard ? "" : "rounded-lg border border-border", withCard ? undefined : className), children: _jsxs(SandpackProvider, { template: "react-ts", files: files, customSetup: sandpackCustomSetup, options: sandpackOptions, children: [_jsx("style", { children: SANDPACK_HOST_STYLES_CSS }), _jsxs("div", { className: "flex items-center justify-between border-b border-border px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [withCard ? null : _jsx("span", { className: "text-sm font-medium", children: title ?? "Example" }), _jsx("span", { className: "text-xs text-muted-foreground", children: codeContract === "renderBody" ? "editable snippet" : "editable App.tsx" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [expandable ? (_jsx(SgButton, { appearance: "outline", size: "sm", onClick: () => setIsExpanded((prev) => !prev), children: isExpanded ? "Reduzir" : "Expandir" })) : null, _jsx(RunButton, { onRun: () => setActivePanel("preview") })] })] }), _jsxs("div", { className: "flex md:hidden border-b border-border", children: [_jsx("button", { type: "button", className: cn("flex-1 py-2 text-sm font-medium border-b-2 -mb-px transition-colors", activePanel === "code"
|
|
389
911
|
? "border-primary text-foreground"
|
|
390
912
|
: "border-transparent text-muted-foreground hover:text-foreground"), onClick: () => setActivePanel("code"), children: "C\u00F3digo" }), _jsx("button", { type: "button", className: cn("flex-1 py-2 text-sm font-medium border-b-2 -mb-px transition-colors", activePanel === "preview"
|
|
391
913
|
? "border-primary text-foreground"
|
|
392
|
-
: "border-transparent text-muted-foreground hover:text-foreground"), onClick: () => setActivePanel("preview"), children: "Preview" })] }), _jsxs("div", { className: cn("grid overflow-auto min-h-[260px]", "grid-cols-1 md:grid-cols-2", resizeClass), style: { height: currentHeight }, children: [_jsxs("div", { className: cn("min-w-0 md:border-r border-border", activePanel !== "code" ? "hidden md:block" : ""), children: [_jsx(SandpackCodeEditor, { showLineNumbers: true, wrapContent: true, showTabs: false, showRunButton: false, style: { height: "100%" } }), _jsx("div", { className: "flex justify-end border-t border-border px-3 py-2", children: _jsx(CopyButton, {}) })] }), _jsx("div", { className: cn("min-w-0", activePanel !== "preview" ? "hidden md:block" : ""), children: _jsx(SandpackPreview, { style: { height: "100%" }, showOpenInCodeSandbox: false, showRefreshButton: false, showRestartButton: false }) })] })] }) })) : (_jsxs("div", { className: cn(withCard ? undefined : "space-y-2", withCard ? undefined : className), children: [withCard ? null : title ? _jsx("div", { className: "text-sm font-medium", children: title }) : null, _jsx(ReadonlyBlock, { code: code })] }));
|
|
914
|
+
: "border-transparent text-muted-foreground hover:text-foreground"), onClick: () => setActivePanel("preview"), children: "Preview" })] }), _jsxs("div", { className: cn("grid overflow-auto min-h-[260px]", "grid-cols-1 md:grid-cols-2", resizeClass), style: { height: currentHeight }, children: [_jsxs("div", { className: cn("min-w-0 md:border-r border-border", activePanel !== "code" ? "hidden md:block" : ""), children: [_jsx(SandpackCodeEditor, { showLineNumbers: true, wrapContent: true, showTabs: false, showRunButton: false, style: { height: "100%" } }), _jsx("div", { className: "flex justify-end border-t border-border px-3 py-2", children: _jsx(CopyButton, {}) })] }), _jsx("div", { className: cn("min-w-0", activePanel !== "preview" ? "hidden md:block" : ""), children: _jsx(SandpackPreview, { className: "sg-playground-preview", style: { height: "100%" }, showOpenInCodeSandbox: false, showRefreshButton: false, showRestartButton: false }) })] })] }) })) : (_jsxs("div", { className: cn(withCard ? undefined : "space-y-2", withCard ? undefined : className), children: [withCard ? null : title ? _jsx("div", { className: "text-sm font-medium", children: title }) : null, _jsx(ReadonlyBlock, { code: code })] }));
|
|
393
915
|
if (!withCard)
|
|
394
916
|
return content;
|
|
395
917
|
return (_jsx(SgCard, { id: cardId, title: title ?? "Codigo", description: description, collapsible: collapsible, defaultOpen: defaultOpen, className: cn("rounded-lg", className), bodyClassName: "p-0", children: content }));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seedgrid/fe-components",
|
|
3
|
-
"version": "2026.3.
|
|
3
|
+
"version": "2026.3.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -29,11 +29,13 @@
|
|
|
29
29
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
+
"@tiptap/core": "^2.9.1",
|
|
32
33
|
"@tiptap/extension-color": "^2.9.1",
|
|
33
34
|
"@tiptap/extension-font-family": "^2.9.1",
|
|
34
35
|
"@tiptap/extension-highlight": "^2.9.1",
|
|
35
36
|
"@tiptap/extension-image": "^2.9.1",
|
|
36
37
|
"@tiptap/extension-link": "^2.9.1",
|
|
38
|
+
"@tiptap/pm": "^2.9.1",
|
|
37
39
|
"@tiptap/extension-subscript": "^2.9.1",
|
|
38
40
|
"@tiptap/extension-superscript": "^2.9.1",
|
|
39
41
|
"@tiptap/extension-text-align": "^2.9.1",
|
|
@@ -46,11 +48,13 @@
|
|
|
46
48
|
"react-hook-form": "^7.0.0"
|
|
47
49
|
},
|
|
48
50
|
"devDependencies": {
|
|
51
|
+
"@tiptap/core": "^2.9.1",
|
|
49
52
|
"@tiptap/extension-color": "^2.9.1",
|
|
50
53
|
"@tiptap/extension-font-family": "^2.9.1",
|
|
51
54
|
"@tiptap/extension-highlight": "^2.9.1",
|
|
52
55
|
"@tiptap/extension-image": "^2.9.1",
|
|
53
56
|
"@tiptap/extension-link": "^2.9.1",
|
|
57
|
+
"@tiptap/pm": "^2.9.1",
|
|
54
58
|
"@tiptap/extension-subscript": "^2.9.1",
|
|
55
59
|
"@tiptap/extension-superscript": "^2.9.1",
|
|
56
60
|
"@tiptap/extension-text-align": "^2.9.1",
|
|
@@ -58,7 +62,6 @@
|
|
|
58
62
|
"@tiptap/extension-underline": "^2.9.1",
|
|
59
63
|
"@tiptap/react": "^2.9.1",
|
|
60
64
|
"@tiptap/starter-kit": "^2.9.1",
|
|
61
|
-
"@types/qrcode": "^1.5.6",
|
|
62
65
|
"lucide-react": "^0.468.0",
|
|
63
66
|
"react": "19.0.0",
|
|
64
67
|
"react-dom": "19.0.0",
|
|
@@ -67,6 +70,6 @@
|
|
|
67
70
|
"dependencies": {
|
|
68
71
|
"@codesandbox/sandpack-react": "^2.20.0",
|
|
69
72
|
"@pqina/flip": "^1.8.4",
|
|
70
|
-
"qrcode": "^
|
|
73
|
+
"qrcode.react": "^4.2.0"
|
|
71
74
|
}
|
|
72
75
|
}
|