@nuvio/overlay 0.5.3 → 0.5.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/index.css +7 -9
- package/dist/index.js +420 -186
- package/dist/style.css +8 -9
- package/package.json +3 -2
package/dist/index.css
CHANGED
|
@@ -1012,21 +1012,16 @@ select.nuvio-control {
|
|
|
1012
1012
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
1013
1013
|
}
|
|
1014
1014
|
.nuvio-color-popover {
|
|
1015
|
-
position: absolute;
|
|
1016
|
-
left: 0;
|
|
1017
|
-
right: 0;
|
|
1018
|
-
z-index: 20;
|
|
1019
|
-
margin-top: 4px;
|
|
1020
|
-
max-height: min(20rem, 50vh);
|
|
1021
1015
|
overflow: auto;
|
|
1022
1016
|
border-radius: var(--nuvio-radius-inner);
|
|
1023
1017
|
border: 1px solid var(--nuvio-border-strong);
|
|
1024
|
-
background:
|
|
1025
|
-
-webkit-backdrop-filter: var(--nuvio-inner-blur);
|
|
1026
|
-
backdrop-filter: var(--nuvio-inner-blur);
|
|
1018
|
+
background: rgb(15, 23, 42);
|
|
1027
1019
|
padding: 10px;
|
|
1028
1020
|
box-shadow: 0 28px 80px rgba(0, 0, 0, 0.42);
|
|
1029
1021
|
}
|
|
1022
|
+
.nuvio-color-popover--fixed {
|
|
1023
|
+
pointer-events: auto;
|
|
1024
|
+
}
|
|
1030
1025
|
.nuvio-color-specials {
|
|
1031
1026
|
display: flex;
|
|
1032
1027
|
flex-wrap: wrap;
|
|
@@ -1136,7 +1131,10 @@ select.nuvio-control {
|
|
|
1136
1131
|
color: var(--nuvio-text-muted);
|
|
1137
1132
|
}
|
|
1138
1133
|
.nuvio-card--actions {
|
|
1134
|
+
position: relative;
|
|
1135
|
+
z-index: 1;
|
|
1139
1136
|
border-color: rgba(56, 189, 248, 0.25);
|
|
1137
|
+
background: rgb(15, 23, 42);
|
|
1140
1138
|
}
|
|
1141
1139
|
.nuvio-action-stack {
|
|
1142
1140
|
display: flex;
|
package/dist/index.js
CHANGED
|
@@ -28,12 +28,12 @@ function loadOverlayStyles() {
|
|
|
28
28
|
import {
|
|
29
29
|
useCallback as useCallback3,
|
|
30
30
|
useEffect as useEffect9,
|
|
31
|
-
useLayoutEffect as
|
|
31
|
+
useLayoutEffect as useLayoutEffect3,
|
|
32
32
|
useMemo as useMemo6,
|
|
33
33
|
useRef as useRef5,
|
|
34
34
|
useState as useState9
|
|
35
35
|
} from "react";
|
|
36
|
-
import { createPortal } from "react-dom";
|
|
36
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
37
37
|
import {
|
|
38
38
|
NUVIO_WS_PATH,
|
|
39
39
|
PROTOCOL_VERSION,
|
|
@@ -409,7 +409,7 @@ function useNuvioShadowMount() {
|
|
|
409
409
|
import {
|
|
410
410
|
useCallback as useCallback2,
|
|
411
411
|
useEffect as useEffect8,
|
|
412
|
-
useLayoutEffect,
|
|
412
|
+
useLayoutEffect as useLayoutEffect2,
|
|
413
413
|
useMemo as useMemo5,
|
|
414
414
|
useRef as useRef4,
|
|
415
415
|
useState as useState8
|
|
@@ -641,6 +641,23 @@ function parseClassNameByBreakpoint(className) {
|
|
|
641
641
|
}
|
|
642
642
|
return buckets;
|
|
643
643
|
}
|
|
644
|
+
function classNameHasResponsiveUtilities(className) {
|
|
645
|
+
const buckets = parseClassNameByBreakpoint(className);
|
|
646
|
+
return BREAKPOINT_ORDER.some((bp) => bp !== "base" && buckets[bp].length > 0);
|
|
647
|
+
}
|
|
648
|
+
var INTERACTIVE_VARIANT_RE = /^(?:hover|focus|focus-within|active|disabled|group-hover|peer-hover|first|last|odd|even):/;
|
|
649
|
+
function isInteractiveVariantToken(token) {
|
|
650
|
+
return INTERACTIVE_VARIANT_RE.test(token);
|
|
651
|
+
}
|
|
652
|
+
function isDarkVariantToken(token) {
|
|
653
|
+
return /^dark:/.test(token);
|
|
654
|
+
}
|
|
655
|
+
function includeDarkVariantsInRead() {
|
|
656
|
+
if (typeof document === "undefined") {
|
|
657
|
+
return false;
|
|
658
|
+
}
|
|
659
|
+
return document.documentElement.classList.contains("dark");
|
|
660
|
+
}
|
|
644
661
|
function stripVariantPrefixes(token) {
|
|
645
662
|
let t = token;
|
|
646
663
|
for (; ; ) {
|
|
@@ -657,18 +674,26 @@ function flattenTokensAtBreakpoint(className, activeBreakpoint) {
|
|
|
657
674
|
const buckets = parseClassNameByBreakpoint(className);
|
|
658
675
|
const idx = BREAKPOINT_ORDER.indexOf(activeBreakpoint);
|
|
659
676
|
const out = [];
|
|
677
|
+
const includeDark = includeDarkVariantsInRead();
|
|
660
678
|
for (const tok of buckets.passthrough) {
|
|
661
|
-
if (
|
|
662
|
-
|
|
679
|
+
if (isInteractiveVariantToken(tok)) {
|
|
680
|
+
continue;
|
|
681
|
+
}
|
|
682
|
+
if (isDarkVariantToken(tok)) {
|
|
683
|
+
if (includeDark) {
|
|
684
|
+
out.push(stripVariantPrefixes(tok));
|
|
685
|
+
}
|
|
686
|
+
continue;
|
|
663
687
|
}
|
|
664
688
|
}
|
|
665
689
|
for (let i = 0; i <= idx; i++) {
|
|
666
690
|
out.push(...buckets[BREAKPOINT_ORDER[i]]);
|
|
667
691
|
}
|
|
668
692
|
for (const tok of buckets.passthrough) {
|
|
669
|
-
if (
|
|
670
|
-
|
|
693
|
+
if (isInteractiveVariantToken(tok) || isDarkVariantToken(tok)) {
|
|
694
|
+
continue;
|
|
671
695
|
}
|
|
696
|
+
out.push(stripVariantPrefixes(tok));
|
|
672
697
|
}
|
|
673
698
|
return out;
|
|
674
699
|
}
|
|
@@ -1166,12 +1191,12 @@ function mapUnsupportedReasonToSimple(reason) {
|
|
|
1166
1191
|
function getSimpleBlockedEditFallback(selectedId, selectedEntry) {
|
|
1167
1192
|
const textContext = selectedEntry?.textEditable === true || selectedId != null && /\.(label|value|nameText|name|price|category|status|title|subtitle)$/.test(selectedId) || selectedId != null && selectedId.includes(".header.");
|
|
1168
1193
|
if (textContext) {
|
|
1169
|
-
return "
|
|
1194
|
+
return "nuvio can't safely edit this text yet.";
|
|
1170
1195
|
}
|
|
1171
|
-
return "
|
|
1196
|
+
return "nuvio can't safely edit this element.";
|
|
1172
1197
|
}
|
|
1173
1198
|
function getSimpleIndexEmptyMessage() {
|
|
1174
|
-
return "Nothing is set up to edit yet. Add
|
|
1199
|
+
return "Nothing is set up to edit yet. Add nuvio ids to elements in your project, then restart the dev server.";
|
|
1175
1200
|
}
|
|
1176
1201
|
function getSimplePatchBlockedMessage(indexIdCount, selectionResolved) {
|
|
1177
1202
|
if (indexIdCount === 0) {
|
|
@@ -1736,7 +1761,7 @@ var REASON_MAP = [
|
|
|
1736
1761
|
{
|
|
1737
1762
|
match: (r) => r.includes("host_not_found") || r.includes("No JSX host"),
|
|
1738
1763
|
message: {
|
|
1739
|
-
sentence: "
|
|
1764
|
+
sentence: "nuvio couldn't find this element in source \u2014 click it again or refresh the page.",
|
|
1740
1765
|
suggestedAction: "addId"
|
|
1741
1766
|
}
|
|
1742
1767
|
},
|
|
@@ -1757,9 +1782,9 @@ var REASON_MAP = [
|
|
|
1757
1782
|
{
|
|
1758
1783
|
match: (r) => r.includes("Unknown or disallowed Tailwind"),
|
|
1759
1784
|
message: {
|
|
1760
|
-
sentence: "This class uses utilities
|
|
1785
|
+
sentence: "This class uses utilities nuvio can't edit yet \u2014 simplify the styles on this element or edit in your code editor.",
|
|
1761
1786
|
suggestedAction: "useHandoff",
|
|
1762
|
-
handoffStep: "Remove or simplify responsive/dark Tailwind classes on this element so
|
|
1787
|
+
handoffStep: "Remove or simplify responsive/dark Tailwind classes on this element so nuvio can edit padding, radius, and shadow."
|
|
1763
1788
|
}
|
|
1764
1789
|
}
|
|
1765
1790
|
];
|
|
@@ -1778,7 +1803,7 @@ function mapReasonToPlainMessage(reason) {
|
|
|
1778
1803
|
}
|
|
1779
1804
|
function getPlainPatchHandoffStep(message) {
|
|
1780
1805
|
if (!message) {
|
|
1781
|
-
return "Review this element in source and fix the styles or
|
|
1806
|
+
return "Review this element in source and fix the styles or nuvio ids.";
|
|
1782
1807
|
}
|
|
1783
1808
|
const stripped = message.replace(/^Error:\s*/i, "").trim();
|
|
1784
1809
|
const mapped = mapReasonToPlainMessage(stripped);
|
|
@@ -2417,7 +2442,7 @@ function buildFixHandoffClipboard(ctx) {
|
|
|
2417
2442
|
const fileLine = ctx.file != null ? `${ctx.file}${ctx.line != null ? `:${ctx.line}` : ""}` : "(unknown file)";
|
|
2418
2443
|
const component = ctx.componentName ?? ctx.hostId;
|
|
2419
2444
|
return [
|
|
2420
|
-
"
|
|
2445
|
+
"nuvio could not apply this edit safely.",
|
|
2421
2446
|
"",
|
|
2422
2447
|
`Component: ${component} (${ctx.hostId})`,
|
|
2423
2448
|
`File: ${fileLine}`,
|
|
@@ -2430,7 +2455,7 @@ function buildFixHandoffClipboard(ctx) {
|
|
|
2430
2455
|
`"In ${ctx.file ?? "the component file"}, ${ctx.suggestedNextStep}"`
|
|
2431
2456
|
].join("\n");
|
|
2432
2457
|
}
|
|
2433
|
-
var MAKE_TABLE_EDITABLE_SNIPPET = `Add
|
|
2458
|
+
var MAKE_TABLE_EDITABLE_SNIPPET = `Add nuvio table ids (v0.4 contract):
|
|
2434
2459
|
- Section wrapper: data-nuvio-id="{host}.section"
|
|
2435
2460
|
- Title h3: data-nuvio-id="{host}.title"
|
|
2436
2461
|
- Table scroll area: data-nuvio-id="{host}.table"
|
|
@@ -2654,7 +2679,7 @@ function HandoffActionBar({
|
|
|
2654
2679
|
file,
|
|
2655
2680
|
line,
|
|
2656
2681
|
componentName,
|
|
2657
|
-
userIntent = "edit selection in
|
|
2682
|
+
userIntent = "edit selection in nuvio",
|
|
2658
2683
|
tableContext = false,
|
|
2659
2684
|
simpleMode = false,
|
|
2660
2685
|
onSwitchTarget,
|
|
@@ -2756,7 +2781,7 @@ function SimpleModeActionBar({
|
|
|
2756
2781
|
// src/selection-guides.ts
|
|
2757
2782
|
var GUIDE_CONTENT = {
|
|
2758
2783
|
welcome: {
|
|
2759
|
-
title: "Welcome to
|
|
2784
|
+
title: "Welcome to nuvio",
|
|
2760
2785
|
body: "Click something on the page \u2192 choose what to change \u2192 Preview Changes \u2192 Apply to Code. Changes save to your source files. Undo anytime. If an area isn't editable, use Copy Fix Prompt."
|
|
2761
2786
|
},
|
|
2762
2787
|
"first-selection": {
|
|
@@ -3801,7 +3826,14 @@ function dismissGuide(id) {
|
|
|
3801
3826
|
}
|
|
3802
3827
|
|
|
3803
3828
|
// src/ColorPickerRow.tsx
|
|
3804
|
-
import {
|
|
3829
|
+
import {
|
|
3830
|
+
useEffect as useEffect7,
|
|
3831
|
+
useId,
|
|
3832
|
+
useLayoutEffect,
|
|
3833
|
+
useRef as useRef3,
|
|
3834
|
+
useState as useState7
|
|
3835
|
+
} from "react";
|
|
3836
|
+
import { createPortal } from "react-dom";
|
|
3805
3837
|
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3806
3838
|
function hexForUtility(value, options) {
|
|
3807
3839
|
if (!value) {
|
|
@@ -3831,6 +3863,29 @@ function hexForUtility(value, options) {
|
|
|
3831
3863
|
function familyLabel(family) {
|
|
3832
3864
|
return family.charAt(0).toUpperCase() + family.slice(1);
|
|
3833
3865
|
}
|
|
3866
|
+
function getOverlayPortalRoot() {
|
|
3867
|
+
const host = document.getElementById(NUVIO_SHADOW_HOST_ID);
|
|
3868
|
+
const mount = host?.shadowRoot?.querySelector(".nuvio-shadow-mount");
|
|
3869
|
+
return mount instanceof HTMLElement ? mount : null;
|
|
3870
|
+
}
|
|
3871
|
+
function measurePopoverBox(trigger) {
|
|
3872
|
+
const rect = trigger.getBoundingClientRect();
|
|
3873
|
+
const margin = 8;
|
|
3874
|
+
const preferredMax = 320;
|
|
3875
|
+
const minWidth = 300;
|
|
3876
|
+
const spaceBelow = window.innerHeight - rect.bottom - margin;
|
|
3877
|
+
const spaceAbove = rect.top - margin;
|
|
3878
|
+
const placeAbove = spaceBelow < 200 && spaceAbove > spaceBelow;
|
|
3879
|
+
const maxHeight = Math.max(120, Math.min(preferredMax, placeAbove ? spaceAbove : spaceBelow));
|
|
3880
|
+
const width = Math.min(Math.max(rect.width, minWidth), window.innerWidth - margin * 2);
|
|
3881
|
+
let left = rect.left;
|
|
3882
|
+
if (left + width > window.innerWidth - margin) {
|
|
3883
|
+
left = window.innerWidth - margin - width;
|
|
3884
|
+
}
|
|
3885
|
+
left = Math.max(margin, left);
|
|
3886
|
+
const top = placeAbove ? Math.max(margin, rect.top - maxHeight - 4) : rect.bottom + 4;
|
|
3887
|
+
return { top, left, width, maxHeight };
|
|
3888
|
+
}
|
|
3834
3889
|
function ColorPickerRow({
|
|
3835
3890
|
label,
|
|
3836
3891
|
value,
|
|
@@ -3840,10 +3895,36 @@ function ColorPickerRow({
|
|
|
3840
3895
|
simpleMode = false
|
|
3841
3896
|
}) {
|
|
3842
3897
|
const [open, setOpen] = useState7(false);
|
|
3898
|
+
const [popoverBox, setPopoverBox] = useState7(null);
|
|
3843
3899
|
const rootRef = useRef3(null);
|
|
3844
3900
|
const listId = useId();
|
|
3845
3901
|
const swatchHex = hexForUtility(value, options);
|
|
3846
3902
|
const displayValue = simpleMode ? value ? options.find((o) => o.value === value)?.label ?? "Custom" : "Default" : value || "\u2014";
|
|
3903
|
+
const updatePopoverBox = () => {
|
|
3904
|
+
const row = rootRef.current;
|
|
3905
|
+
if (!row) {
|
|
3906
|
+
return;
|
|
3907
|
+
}
|
|
3908
|
+
const trigger = row.querySelector(".nuvio-color-trigger");
|
|
3909
|
+
if (!(trigger instanceof HTMLElement)) {
|
|
3910
|
+
return;
|
|
3911
|
+
}
|
|
3912
|
+
setPopoverBox(measurePopoverBox(trigger));
|
|
3913
|
+
};
|
|
3914
|
+
useLayoutEffect(() => {
|
|
3915
|
+
if (!open) {
|
|
3916
|
+
setPopoverBox(null);
|
|
3917
|
+
return;
|
|
3918
|
+
}
|
|
3919
|
+
updatePopoverBox();
|
|
3920
|
+
window.addEventListener("resize", updatePopoverBox);
|
|
3921
|
+
const panelBody = rootRef.current?.closest(".nuvio-panel-body");
|
|
3922
|
+
panelBody?.addEventListener("scroll", updatePopoverBox, { passive: true });
|
|
3923
|
+
return () => {
|
|
3924
|
+
window.removeEventListener("resize", updatePopoverBox);
|
|
3925
|
+
panelBody?.removeEventListener("scroll", updatePopoverBox);
|
|
3926
|
+
};
|
|
3927
|
+
}, [open]);
|
|
3847
3928
|
useEffect7(() => {
|
|
3848
3929
|
if (!open) {
|
|
3849
3930
|
return;
|
|
@@ -3854,7 +3935,9 @@ function ColorPickerRow({
|
|
|
3854
3935
|
return;
|
|
3855
3936
|
}
|
|
3856
3937
|
const path = typeof e.composedPath === "function" ? e.composedPath() : [];
|
|
3857
|
-
const clickedInside = path.includes(root) || root.contains(e.target)
|
|
3938
|
+
const clickedInside = path.includes(root) || root.contains(e.target) || path.some(
|
|
3939
|
+
(node) => node instanceof HTMLElement && (node.id === listId || node.classList.contains("nuvio-color-popover"))
|
|
3940
|
+
);
|
|
3858
3941
|
if (!clickedInside) {
|
|
3859
3942
|
setOpen(false);
|
|
3860
3943
|
}
|
|
@@ -3869,6 +3952,89 @@ function ColorPickerRow({
|
|
|
3869
3952
|
onChange(next);
|
|
3870
3953
|
setOpen(false);
|
|
3871
3954
|
};
|
|
3955
|
+
const popoverStyle = popoverBox ? {
|
|
3956
|
+
position: "fixed",
|
|
3957
|
+
top: popoverBox.top,
|
|
3958
|
+
left: popoverBox.left,
|
|
3959
|
+
width: popoverBox.width,
|
|
3960
|
+
maxHeight: popoverBox.maxHeight,
|
|
3961
|
+
zIndex: 2147483640
|
|
3962
|
+
} : void 0;
|
|
3963
|
+
const popover = open && popoverBox ? /* @__PURE__ */ jsxs13(
|
|
3964
|
+
"div",
|
|
3965
|
+
{
|
|
3966
|
+
id: listId,
|
|
3967
|
+
role: "listbox",
|
|
3968
|
+
"aria-label": `${label} palette`,
|
|
3969
|
+
className: "nuvio-color-popover nuvio-color-popover--fixed",
|
|
3970
|
+
style: popoverStyle,
|
|
3971
|
+
children: [
|
|
3972
|
+
!simpleMode ? /* @__PURE__ */ jsxs13(
|
|
3973
|
+
"p",
|
|
3974
|
+
{
|
|
3975
|
+
className: "nuvio-text-3xs nuvio-leading-snug nuvio-text-muted",
|
|
3976
|
+
style: { marginBottom: 8 },
|
|
3977
|
+
children: [
|
|
3978
|
+
"Tailwind palette \u2014 picks a utility class (e.g. ",
|
|
3979
|
+
utilityPrefix,
|
|
3980
|
+
"-sky-500), not a custom hex value."
|
|
3981
|
+
]
|
|
3982
|
+
}
|
|
3983
|
+
) : null,
|
|
3984
|
+
/* @__PURE__ */ jsx13("div", { className: "nuvio-color-specials", children: specials.map((o) => /* @__PURE__ */ jsxs13(
|
|
3985
|
+
"button",
|
|
3986
|
+
{
|
|
3987
|
+
type: "button",
|
|
3988
|
+
role: "option",
|
|
3989
|
+
"aria-selected": value === o.value,
|
|
3990
|
+
title: o.label,
|
|
3991
|
+
className: `nuvio-color-special-btn ${value === o.value ? "nuvio-color-special-btn--active" : ""}`,
|
|
3992
|
+
onClick: () => pick(o.value),
|
|
3993
|
+
children: [
|
|
3994
|
+
/* @__PURE__ */ jsx13("span", { className: "nuvio-color-swatch--sm", style: { backgroundColor: o.hex } }),
|
|
3995
|
+
o.label
|
|
3996
|
+
]
|
|
3997
|
+
},
|
|
3998
|
+
o.value || "__none"
|
|
3999
|
+
)) }),
|
|
4000
|
+
/* @__PURE__ */ jsxs13(
|
|
4001
|
+
"div",
|
|
4002
|
+
{
|
|
4003
|
+
className: "nuvio-palette-grid",
|
|
4004
|
+
style: {
|
|
4005
|
+
gridTemplateColumns: `3.25rem repeat(${TAILWIND_COLOR_SHADES.length}, minmax(0, 1fr))`
|
|
4006
|
+
},
|
|
4007
|
+
children: [
|
|
4008
|
+
/* @__PURE__ */ jsx13("span", {}),
|
|
4009
|
+
TAILWIND_COLOR_SHADES.map((s) => /* @__PURE__ */ jsx13("span", { className: "nuvio-palette-shade", children: s }, s)),
|
|
4010
|
+
TAILWIND_COLOR_FAMILIES.map((family) => /* @__PURE__ */ jsxs13("div", { className: "nuvio-palette-contents", children: [
|
|
4011
|
+
/* @__PURE__ */ jsx13("span", { className: "nuvio-palette-family", children: familyLabel(family) }),
|
|
4012
|
+
TAILWIND_COLOR_SHADES.map((shade) => {
|
|
4013
|
+
const util = `${utilityPrefix}-${family}-${shade}`;
|
|
4014
|
+
const hex = TAILWIND_PALETTE_HEX[family][String(shade)];
|
|
4015
|
+
const selected = value === util || value.replace(/\/(?:\d+|\[[\d.]+\])$/, "") === util;
|
|
4016
|
+
return /* @__PURE__ */ jsx13(
|
|
4017
|
+
"button",
|
|
4018
|
+
{
|
|
4019
|
+
type: "button",
|
|
4020
|
+
role: "option",
|
|
4021
|
+
"aria-selected": selected,
|
|
4022
|
+
title: simpleMode ? `${familyLabel(family)} ${shade}` : util,
|
|
4023
|
+
className: `nuvio-palette-swatch ${selected ? "nuvio-palette-swatch--selected" : ""}`,
|
|
4024
|
+
style: { backgroundColor: hex },
|
|
4025
|
+
onClick: () => pick(util)
|
|
4026
|
+
},
|
|
4027
|
+
util
|
|
4028
|
+
);
|
|
4029
|
+
})
|
|
4030
|
+
] }, family))
|
|
4031
|
+
]
|
|
4032
|
+
}
|
|
4033
|
+
)
|
|
4034
|
+
]
|
|
4035
|
+
}
|
|
4036
|
+
) : null;
|
|
4037
|
+
const portalRoot = open ? getOverlayPortalRoot() : null;
|
|
3872
4038
|
return /* @__PURE__ */ jsxs13("div", { ref: rootRef, className: "nuvio-field-row nuvio-field-row--start", children: [
|
|
3873
4039
|
/* @__PURE__ */ jsx13("span", { className: "nuvio-label nuvio-label--pad-top", children: label }),
|
|
3874
4040
|
/* @__PURE__ */ jsxs13("div", { className: "nuvio-min-w-0 nuvio-relative", children: [
|
|
@@ -3899,84 +4065,15 @@ function ColorPickerRow({
|
|
|
3899
4065
|
]
|
|
3900
4066
|
}
|
|
3901
4067
|
),
|
|
3902
|
-
|
|
3903
|
-
"div",
|
|
3904
|
-
{
|
|
3905
|
-
id: listId,
|
|
3906
|
-
role: "listbox",
|
|
3907
|
-
"aria-label": `${label} palette`,
|
|
3908
|
-
className: "nuvio-color-popover",
|
|
3909
|
-
children: [
|
|
3910
|
-
!simpleMode ? /* @__PURE__ */ jsxs13("p", { className: "nuvio-text-3xs nuvio-leading-snug nuvio-text-muted", style: { marginBottom: 8 }, children: [
|
|
3911
|
-
"Tailwind palette \u2014 picks a utility class (e.g. ",
|
|
3912
|
-
utilityPrefix,
|
|
3913
|
-
"-sky-500), not a custom hex value."
|
|
3914
|
-
] }) : null,
|
|
3915
|
-
/* @__PURE__ */ jsx13("div", { className: "nuvio-color-specials", children: specials.map((o) => /* @__PURE__ */ jsxs13(
|
|
3916
|
-
"button",
|
|
3917
|
-
{
|
|
3918
|
-
type: "button",
|
|
3919
|
-
role: "option",
|
|
3920
|
-
"aria-selected": value === o.value,
|
|
3921
|
-
title: o.label,
|
|
3922
|
-
className: `nuvio-color-special-btn ${value === o.value ? "nuvio-color-special-btn--active" : ""}`,
|
|
3923
|
-
onClick: () => pick(o.value),
|
|
3924
|
-
children: [
|
|
3925
|
-
/* @__PURE__ */ jsx13(
|
|
3926
|
-
"span",
|
|
3927
|
-
{
|
|
3928
|
-
className: "nuvio-color-swatch--sm",
|
|
3929
|
-
style: { backgroundColor: o.hex }
|
|
3930
|
-
}
|
|
3931
|
-
),
|
|
3932
|
-
o.label
|
|
3933
|
-
]
|
|
3934
|
-
},
|
|
3935
|
-
o.value || "__none"
|
|
3936
|
-
)) }),
|
|
3937
|
-
/* @__PURE__ */ jsxs13(
|
|
3938
|
-
"div",
|
|
3939
|
-
{
|
|
3940
|
-
className: "nuvio-palette-grid",
|
|
3941
|
-
style: {
|
|
3942
|
-
gridTemplateColumns: `3.25rem repeat(${TAILWIND_COLOR_SHADES.length}, minmax(0, 1fr))`
|
|
3943
|
-
},
|
|
3944
|
-
children: [
|
|
3945
|
-
/* @__PURE__ */ jsx13("span", {}),
|
|
3946
|
-
TAILWIND_COLOR_SHADES.map((s) => /* @__PURE__ */ jsx13("span", { className: "nuvio-palette-shade", children: s }, s)),
|
|
3947
|
-
TAILWIND_COLOR_FAMILIES.map((family) => /* @__PURE__ */ jsxs13("div", { className: "nuvio-palette-contents", children: [
|
|
3948
|
-
/* @__PURE__ */ jsx13("span", { className: "nuvio-palette-family", children: familyLabel(family) }),
|
|
3949
|
-
TAILWIND_COLOR_SHADES.map((shade) => {
|
|
3950
|
-
const util = `${utilityPrefix}-${family}-${shade}`;
|
|
3951
|
-
const hex = TAILWIND_PALETTE_HEX[family][String(shade)];
|
|
3952
|
-
const selected = value === util || value.replace(/\/(?:\d+|\[[\d.]+\])$/, "") === util;
|
|
3953
|
-
return /* @__PURE__ */ jsx13(
|
|
3954
|
-
"button",
|
|
3955
|
-
{
|
|
3956
|
-
type: "button",
|
|
3957
|
-
role: "option",
|
|
3958
|
-
"aria-selected": selected,
|
|
3959
|
-
title: simpleMode ? `${familyLabel(family)} ${shade}` : util,
|
|
3960
|
-
className: `nuvio-palette-swatch ${selected ? "nuvio-palette-swatch--selected" : ""}`,
|
|
3961
|
-
style: { backgroundColor: hex },
|
|
3962
|
-
onClick: () => pick(util)
|
|
3963
|
-
},
|
|
3964
|
-
util
|
|
3965
|
-
);
|
|
3966
|
-
})
|
|
3967
|
-
] }, family))
|
|
3968
|
-
]
|
|
3969
|
-
}
|
|
3970
|
-
)
|
|
3971
|
-
]
|
|
3972
|
-
}
|
|
3973
|
-
) : null
|
|
4068
|
+
portalRoot && popover ? createPortal(popover, portalRoot) : null
|
|
3974
4069
|
] })
|
|
3975
4070
|
] });
|
|
3976
4071
|
}
|
|
3977
4072
|
|
|
3978
4073
|
// src/PropertyPanelShell.tsx
|
|
3979
4074
|
import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
4075
|
+
var NUVO_PREVIEW_CHANGES_LABEL = "Preview Changes";
|
|
4076
|
+
var NUVO_APPLY_TO_CODE_LABEL = "Apply to Code";
|
|
3980
4077
|
function assignShellRef(shellRef, el) {
|
|
3981
4078
|
shellRef.current = el;
|
|
3982
4079
|
}
|
|
@@ -4015,6 +4112,77 @@ function SelectRow({
|
|
|
4015
4112
|
)
|
|
4016
4113
|
] });
|
|
4017
4114
|
}
|
|
4115
|
+
function DeviceBreakpointPanel({
|
|
4116
|
+
devicePreset,
|
|
4117
|
+
onDevicePresetChange,
|
|
4118
|
+
activeBreakpoint,
|
|
4119
|
+
onActiveBreakpointChange,
|
|
4120
|
+
developerDetails,
|
|
4121
|
+
variant
|
|
4122
|
+
}) {
|
|
4123
|
+
const controls = /* @__PURE__ */ jsxs14(Fragment5, { children: [
|
|
4124
|
+
/* @__PURE__ */ jsxs14("div", { className: "nuvio-row-wrap", children: [
|
|
4125
|
+
/* @__PURE__ */ jsx14(
|
|
4126
|
+
"button",
|
|
4127
|
+
{
|
|
4128
|
+
type: "button",
|
|
4129
|
+
className: `nuvio-button-chip ${devicePreset === "desktop" ? "nuvio-button-chip--active" : ""}`,
|
|
4130
|
+
onClick: () => onDevicePresetChange("desktop"),
|
|
4131
|
+
children: "Desktop"
|
|
4132
|
+
}
|
|
4133
|
+
),
|
|
4134
|
+
/* @__PURE__ */ jsx14(
|
|
4135
|
+
"button",
|
|
4136
|
+
{
|
|
4137
|
+
type: "button",
|
|
4138
|
+
className: `nuvio-button-chip ${devicePreset === "tablet" ? "nuvio-button-chip--active" : ""}`,
|
|
4139
|
+
onClick: () => onDevicePresetChange("tablet"),
|
|
4140
|
+
children: "Tablet"
|
|
4141
|
+
}
|
|
4142
|
+
),
|
|
4143
|
+
/* @__PURE__ */ jsx14(
|
|
4144
|
+
"button",
|
|
4145
|
+
{
|
|
4146
|
+
type: "button",
|
|
4147
|
+
className: `nuvio-button-chip ${devicePreset === "mobile" ? "nuvio-button-chip--active" : ""}`,
|
|
4148
|
+
onClick: () => onDevicePresetChange("mobile"),
|
|
4149
|
+
children: "Mobile"
|
|
4150
|
+
}
|
|
4151
|
+
)
|
|
4152
|
+
] }),
|
|
4153
|
+
/* @__PURE__ */ jsx14(
|
|
4154
|
+
SelectRow,
|
|
4155
|
+
{
|
|
4156
|
+
label: developerDetails ? "Active BP" : "Applies on",
|
|
4157
|
+
value: activeBreakpoint,
|
|
4158
|
+
onChange: (v) => onActiveBreakpointChange(v),
|
|
4159
|
+
options: [
|
|
4160
|
+
{ value: "base", label: developerDetails ? "base" : formatPlainBreakpointLabel("base") },
|
|
4161
|
+
{ value: "sm", label: developerDetails ? "sm" : formatPlainBreakpointLabel("sm") },
|
|
4162
|
+
{ value: "md", label: developerDetails ? "md" : formatPlainBreakpointLabel("md") },
|
|
4163
|
+
{ value: "lg", label: developerDetails ? "lg" : formatPlainBreakpointLabel("lg") },
|
|
4164
|
+
{ value: "xl", label: developerDetails ? "xl" : formatPlainBreakpointLabel("xl") }
|
|
4165
|
+
],
|
|
4166
|
+
developerDetails
|
|
4167
|
+
}
|
|
4168
|
+
),
|
|
4169
|
+
!developerDetails ? /* @__PURE__ */ jsxs14("p", { className: "nuvio-text-2xs nuvio-text-muted", children: [
|
|
4170
|
+
"Applies on:",
|
|
4171
|
+
" ",
|
|
4172
|
+
/* @__PURE__ */ jsx14("span", { className: "nuvio-font-medium", children: formatPlainBreakpointLabel(activeBreakpoint) })
|
|
4173
|
+
] }) : null
|
|
4174
|
+
] });
|
|
4175
|
+
if (variant === "compact") {
|
|
4176
|
+
return /* @__PURE__ */ jsxs14("div", { className: "nuvio-stack-1", children: [
|
|
4177
|
+
/* @__PURE__ */ jsx14("p", { className: "nuvio-label", children: "Responsive preview" }),
|
|
4178
|
+
controls
|
|
4179
|
+
] });
|
|
4180
|
+
}
|
|
4181
|
+
return /* @__PURE__ */ jsxs14("section", { className: "nuvio-card nuvio-stack-2", children: [
|
|
4182
|
+
/* @__PURE__ */ jsx14("h3", { className: "nuvio-section-title", children: "Device + breakpoint" }),
|
|
4183
|
+
controls
|
|
4184
|
+
] });
|
|
4185
|
+
}
|
|
4018
4186
|
function PropertyPanelShell({
|
|
4019
4187
|
devicePreset,
|
|
4020
4188
|
onDevicePresetChange,
|
|
@@ -4130,8 +4298,8 @@ function PropertyPanelShell({
|
|
|
4130
4298
|
buildHumanPreviewLines({ baselineText, draftText, baselinePicks, draftPicks: picks })
|
|
4131
4299
|
);
|
|
4132
4300
|
}, [baselinePicks, baselineText, developerDetails, draftText, picks]);
|
|
4133
|
-
const previewButtonLabel =
|
|
4134
|
-
const applyButtonLabel =
|
|
4301
|
+
const previewButtonLabel = NUVO_PREVIEW_CHANGES_LABEL;
|
|
4302
|
+
const applyButtonLabel = NUVO_APPLY_TO_CODE_LABEL;
|
|
4135
4303
|
const simpleMode = !developerDetails;
|
|
4136
4304
|
const selectionTitle = selectedId && selectedEntry ? formatSelectionTitle(selectedId, selectedEntry, indexEntries) : null;
|
|
4137
4305
|
const showEditSection = selectedId && !missing && (developerDetails || !taskRouter.active || taskRouter.showTaskControls);
|
|
@@ -4197,6 +4365,20 @@ function PropertyPanelShell({
|
|
|
4197
4365
|
}
|
|
4198
4366
|
return containerStyleId ?? textStyleId ?? selectedId;
|
|
4199
4367
|
}, [containerStyleId, selectedId, styleTargetMode, textStyleId]);
|
|
4368
|
+
const [styleHostClassName, setStyleHostClassName] = useState8("");
|
|
4369
|
+
useEffect8(() => {
|
|
4370
|
+
if (!selectedId) {
|
|
4371
|
+
setStyleHostClassName("");
|
|
4372
|
+
return;
|
|
4373
|
+
}
|
|
4374
|
+
const styleId = patchStyleId ?? selectedId;
|
|
4375
|
+
const el = document.querySelector(`[data-nuvio-id="${escapeAttrSelector(styleId)}"]`);
|
|
4376
|
+
setStyleHostClassName(el instanceof HTMLElement ? el.className : "");
|
|
4377
|
+
}, [selectedId, patchStyleId, stagedVersion]);
|
|
4378
|
+
const showResponsiveDeviceControls = useMemo5(
|
|
4379
|
+
() => classNameHasResponsiveUtilities(styleHostClassName),
|
|
4380
|
+
[styleHostClassName]
|
|
4381
|
+
);
|
|
4200
4382
|
useEffect8(() => {
|
|
4201
4383
|
if (!selectedId) {
|
|
4202
4384
|
setMissing(false);
|
|
@@ -4303,12 +4485,12 @@ function PropertyPanelShell({
|
|
|
4303
4485
|
}
|
|
4304
4486
|
if (hasText && !patchTextId) {
|
|
4305
4487
|
return {
|
|
4306
|
-
error: developerDetails ? "Text cannot be patched for this target \u2014 add a data-nuvio-id on the text element." : "
|
|
4488
|
+
error: developerDetails ? "Text cannot be patched for this target \u2014 add a data-nuvio-id on the text element." : "nuvio can't safely edit this text yet."
|
|
4307
4489
|
};
|
|
4308
4490
|
}
|
|
4309
4491
|
if (hasStyle && !patchStyleId) {
|
|
4310
4492
|
return {
|
|
4311
|
-
error: developerDetails ? "Styles cannot be patched for this target." : "
|
|
4493
|
+
error: developerDetails ? "Styles cannot be patched for this target." : "nuvio can't safely edit this area yet."
|
|
4312
4494
|
};
|
|
4313
4495
|
}
|
|
4314
4496
|
if (hasText && patchTextId) {
|
|
@@ -4325,7 +4507,7 @@ function PropertyPanelShell({
|
|
|
4325
4507
|
}
|
|
4326
4508
|
if (hasText && hasStyle && patchTextId !== patchStyleId) {
|
|
4327
4509
|
return {
|
|
4328
|
-
error: developerDetails ? "Text and styles target different elements.
|
|
4510
|
+
error: developerDetails ? "Text and styles target different elements. Preview and apply text first, then edit styles (or pick a single element in Edit target)." : "Text and styles apply to different parts. Preview text first, then change styles."
|
|
4329
4511
|
};
|
|
4330
4512
|
}
|
|
4331
4513
|
const id = hasText ? patchTextId : patchStyleId;
|
|
@@ -4422,7 +4604,7 @@ function PropertyPanelShell({
|
|
|
4422
4604
|
]
|
|
4423
4605
|
);
|
|
4424
4606
|
const showWelcome = shouldShowWelcome({ developerDetails, dismissed: dismissedGuides });
|
|
4425
|
-
const patchBlockedReason = indexIdCount === 0 ? "Source index has 0 ids \u2014 the dev server cannot map data-nuvio-id to files. Run pnpm dev from the repo root (builds packages), then hard-refresh. Check the terminal for [
|
|
4607
|
+
const patchBlockedReason = indexIdCount === 0 ? "Source index has 0 ids \u2014 the dev server cannot map data-nuvio-id to files. Run pnpm dev from the repo root (builds packages), then hard-refresh. Check the terminal for [nuvio] index warnings." : selectedId && !selectionResolved ? selectError ?? "Server did not confirm this id (no source file). Patches stay disabled until selection succeeds." : null;
|
|
4426
4608
|
const displayPatchBlockedReason = developerDetails ? patchBlockedReason : getSimplePatchBlockedMessage(indexIdCount, selectionResolved) ?? (selectError ? getSimpleSelectErrorMessage(selectError) : null);
|
|
4427
4609
|
const previewApplyMismatch = hasStagedOps && selectionResolved && channelReady && indexIdCount > 0 && (!previewSummary || previewError != null || previewValidatedFingerprint !== stagedOpsFingerprint);
|
|
4428
4610
|
const patchTargetConflict = textEditable && draftText !== baselineText && alphaPicksDiffer(picks, baselinePicks) && patchTextId != null && patchStyleId != null && patchTextId !== patchStyleId;
|
|
@@ -4465,7 +4647,7 @@ function PropertyPanelShell({
|
|
|
4465
4647
|
canMoveDown: false,
|
|
4466
4648
|
peerCount: 0
|
|
4467
4649
|
}));
|
|
4468
|
-
|
|
4650
|
+
useLayoutEffect2(() => {
|
|
4469
4651
|
if (!selectedId || missing) {
|
|
4470
4652
|
setSiblingMove({ canMoveUp: false, canMoveDown: false, peerCount: 0 });
|
|
4471
4653
|
return;
|
|
@@ -4973,8 +5155,8 @@ function PropertyPanelShell({
|
|
|
4973
5155
|
" after each edit so the summary matches what you apply."
|
|
4974
5156
|
] }) : null,
|
|
4975
5157
|
hasStagedOps && !displayPatchBlockedReason && previewApplyMismatch && simpleMode ? /* @__PURE__ */ jsx14("p", { className: "nuvio-text-2xs nuvio-text-muted", children: "Preview your changes before applying." }) : null,
|
|
4976
|
-
patchTargetConflict ? /* @__PURE__ */ jsx14("p", { className: "nuvio-banner nuvio-banner--warn nuvio-text-2xs nuvio-leading-snug", children: developerDetails ? "Text and styles apply to different elements.
|
|
4977
|
-
patchTargetError ? /* @__PURE__ */ jsx14("p", { className: "nuvio-banner nuvio-banner--error nuvio-text-2xs", children: developerDetails ? patchTargetError : patchTargetError.startsWith("
|
|
5158
|
+
patchTargetConflict ? /* @__PURE__ */ jsx14("p", { className: "nuvio-banner nuvio-banner--warn nuvio-text-2xs nuvio-leading-snug", children: developerDetails ? "Text and styles apply to different elements. Preview text first, then change styles \u2014 or pick one target in Edit target." : "Text and styles apply to different parts. Preview text first, then change styles." }) : null,
|
|
5159
|
+
patchTargetError ? /* @__PURE__ */ jsx14("p", { className: "nuvio-banner nuvio-banner--error nuvio-text-2xs", children: developerDetails ? patchTargetError : patchTargetError.startsWith("nuvio can't") || patchTargetError.startsWith("Nothing") || patchTargetError.startsWith("No changes") || patchTargetError.startsWith("Text and styles") || patchTargetError.startsWith("This part") ? patchTargetError : getSimpleSelectErrorMessage(patchTargetError) ?? patchTargetError }) : null,
|
|
4978
5160
|
patchStyleId && selectedId && patchStyleId !== selectedId && developerDetails ? /* @__PURE__ */ jsxs14("p", { className: "nuvio-text-2xs nuvio-text-muted nuvio-leading-snug", children: [
|
|
4979
5161
|
"Styles apply to",
|
|
4980
5162
|
" ",
|
|
@@ -5379,7 +5561,7 @@ function PropertyPanelShell({
|
|
|
5379
5561
|
] })
|
|
5380
5562
|
] }) : null,
|
|
5381
5563
|
previewSummary && !structuralPreviewActive && developerDetails ? /* @__PURE__ */ jsxs14("div", { className: "nuvio-preview-box", children: [
|
|
5382
|
-
/* @__PURE__ */ jsx14("p", { className: "nuvio-preview-box-title", children:
|
|
5564
|
+
/* @__PURE__ */ jsx14("p", { className: "nuvio-preview-box-title", children: "Ready to apply" }),
|
|
5383
5565
|
/* @__PURE__ */ jsx14("p", { className: "nuvio-preview-box-body", children: developerDetails ? previewSummary : humanPreviewBlock || previewSummary })
|
|
5384
5566
|
] }) : null,
|
|
5385
5567
|
developerDetails ? /* @__PURE__ */ jsxs14("div", { className: "nuvio-row-wrap nuvio-pt-2", children: [
|
|
@@ -5506,29 +5688,17 @@ function PropertyPanelShell({
|
|
|
5506
5688
|
simpleMode && selectedId ? /* @__PURE__ */ jsxs14("details", { className: "nuvio-card nuvio-advanced-panel", children: [
|
|
5507
5689
|
/* @__PURE__ */ jsx14("summary", { className: "nuvio-section-title nuvio-advanced-summary", children: "Advanced" }),
|
|
5508
5690
|
/* @__PURE__ */ jsxs14("div", { className: "nuvio-stack-2 nuvio-pt-1", children: [
|
|
5509
|
-
/* @__PURE__ */
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
),
|
|
5521
|
-
/* @__PURE__ */ jsx14(
|
|
5522
|
-
"button",
|
|
5523
|
-
{
|
|
5524
|
-
type: "button",
|
|
5525
|
-
className: `nuvio-button-chip ${devicePreset === "mobile" ? "nuvio-button-chip--active" : ""}`,
|
|
5526
|
-
onClick: () => onDevicePresetChange("mobile"),
|
|
5527
|
-
children: "Mobile"
|
|
5528
|
-
}
|
|
5529
|
-
)
|
|
5530
|
-
] })
|
|
5531
|
-
] }),
|
|
5691
|
+
showResponsiveDeviceControls ? /* @__PURE__ */ jsx14(
|
|
5692
|
+
DeviceBreakpointPanel,
|
|
5693
|
+
{
|
|
5694
|
+
variant: "compact",
|
|
5695
|
+
devicePreset,
|
|
5696
|
+
onDevicePresetChange,
|
|
5697
|
+
activeBreakpoint,
|
|
5698
|
+
onActiveBreakpointChange,
|
|
5699
|
+
developerDetails: false
|
|
5700
|
+
}
|
|
5701
|
+
) : null,
|
|
5532
5702
|
showQuickStyle ? /* @__PURE__ */ jsxs14(Fragment5, { children: [
|
|
5533
5703
|
/* @__PURE__ */ jsx14(
|
|
5534
5704
|
ColorPickerRow,
|
|
@@ -5599,58 +5769,17 @@ function PropertyPanelShell({
|
|
|
5599
5769
|
] })
|
|
5600
5770
|
] }) : null,
|
|
5601
5771
|
!simpleMode ? /* @__PURE__ */ jsxs14(Fragment5, { children: [
|
|
5602
|
-
/* @__PURE__ */
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
),
|
|
5614
|
-
/* @__PURE__ */ jsx14(
|
|
5615
|
-
"button",
|
|
5616
|
-
{
|
|
5617
|
-
type: "button",
|
|
5618
|
-
className: `nuvio-button-chip ${devicePreset === "tablet" ? "nuvio-button-chip--active" : ""}`,
|
|
5619
|
-
onClick: () => onDevicePresetChange("tablet"),
|
|
5620
|
-
children: "Tablet"
|
|
5621
|
-
}
|
|
5622
|
-
),
|
|
5623
|
-
/* @__PURE__ */ jsx14(
|
|
5624
|
-
"button",
|
|
5625
|
-
{
|
|
5626
|
-
type: "button",
|
|
5627
|
-
className: `nuvio-button-chip ${devicePreset === "mobile" ? "nuvio-button-chip--active" : ""}`,
|
|
5628
|
-
onClick: () => onDevicePresetChange("mobile"),
|
|
5629
|
-
children: "Mobile"
|
|
5630
|
-
}
|
|
5631
|
-
)
|
|
5632
|
-
] }),
|
|
5633
|
-
/* @__PURE__ */ jsx14(
|
|
5634
|
-
SelectRow,
|
|
5635
|
-
{
|
|
5636
|
-
label: developerDetails ? "Active BP" : "Applies on",
|
|
5637
|
-
value: activeBreakpoint,
|
|
5638
|
-
onChange: (v) => onActiveBreakpointChange(v),
|
|
5639
|
-
options: [
|
|
5640
|
-
{ value: "base", label: developerDetails ? "base" : formatPlainBreakpointLabel("base") },
|
|
5641
|
-
{ value: "sm", label: developerDetails ? "sm" : formatPlainBreakpointLabel("sm") },
|
|
5642
|
-
{ value: "md", label: developerDetails ? "md" : formatPlainBreakpointLabel("md") },
|
|
5643
|
-
{ value: "lg", label: developerDetails ? "lg" : formatPlainBreakpointLabel("lg") },
|
|
5644
|
-
{ value: "xl", label: developerDetails ? "xl" : formatPlainBreakpointLabel("xl") }
|
|
5645
|
-
]
|
|
5646
|
-
}
|
|
5647
|
-
),
|
|
5648
|
-
!developerDetails ? /* @__PURE__ */ jsxs14("p", { className: "nuvio-text-2xs nuvio-text-muted", children: [
|
|
5649
|
-
"Applies on:",
|
|
5650
|
-
" ",
|
|
5651
|
-
/* @__PURE__ */ jsx14("span", { className: "nuvio-font-medium", children: formatPlainBreakpointLabel(activeBreakpoint) })
|
|
5652
|
-
] }) : null
|
|
5653
|
-
] }),
|
|
5772
|
+
showResponsiveDeviceControls ? /* @__PURE__ */ jsx14(
|
|
5773
|
+
DeviceBreakpointPanel,
|
|
5774
|
+
{
|
|
5775
|
+
variant: "section",
|
|
5776
|
+
devicePreset,
|
|
5777
|
+
onDevicePresetChange,
|
|
5778
|
+
activeBreakpoint,
|
|
5779
|
+
onActiveBreakpointChange,
|
|
5780
|
+
developerDetails
|
|
5781
|
+
}
|
|
5782
|
+
) : null,
|
|
5654
5783
|
selectedId ? /* @__PURE__ */ jsxs14("section", { className: "nuvio-card nuvio-card--tree", children: [
|
|
5655
5784
|
/* @__PURE__ */ jsx14("h3", { className: "nuvio-section-title", children: "Component tree" }),
|
|
5656
5785
|
/* @__PURE__ */ jsx14(
|
|
@@ -5693,6 +5822,100 @@ function saveDeveloperDetails(enabled) {
|
|
|
5693
5822
|
}
|
|
5694
5823
|
}
|
|
5695
5824
|
|
|
5825
|
+
// src/telemetry.ts
|
|
5826
|
+
import { posthog } from "posthog-js";
|
|
5827
|
+
|
|
5828
|
+
// src/nuvio-posthog-token.ts
|
|
5829
|
+
var NUVIO_POSTHOG_TOKEN = "phc_CJnWrLU4hB4aA88DJrPnma2WBMQqVHxUMVvrsye3R6x2";
|
|
5830
|
+
|
|
5831
|
+
// src/telemetry.ts
|
|
5832
|
+
var POSTHOG_HOST = "https://us.i.posthog.com";
|
|
5833
|
+
var initialized = false;
|
|
5834
|
+
var firstSelectionSent = false;
|
|
5835
|
+
var overlayConnectedSent = false;
|
|
5836
|
+
function posthogToken() {
|
|
5837
|
+
return NUVIO_POSTHOG_TOKEN;
|
|
5838
|
+
}
|
|
5839
|
+
function tokenIsConfigured(token) {
|
|
5840
|
+
return Boolean(token && token.startsWith("phc_"));
|
|
5841
|
+
}
|
|
5842
|
+
function isOverlayTelemetryOptedOut(flags) {
|
|
5843
|
+
return flags.localStorageTelemetry === "0" || flags.viteTelemetry === "0";
|
|
5844
|
+
}
|
|
5845
|
+
function isOverlayTelemetryEnabled() {
|
|
5846
|
+
try {
|
|
5847
|
+
const localStorageTelemetry = typeof localStorage !== "undefined" ? localStorage.getItem("nuvio.telemetry") : null;
|
|
5848
|
+
const env = import.meta;
|
|
5849
|
+
if (isOverlayTelemetryOptedOut({
|
|
5850
|
+
localStorageTelemetry,
|
|
5851
|
+
viteTelemetry: env.env?.VITE_NUVIO_TELEMETRY
|
|
5852
|
+
})) {
|
|
5853
|
+
return false;
|
|
5854
|
+
}
|
|
5855
|
+
return true;
|
|
5856
|
+
} catch {
|
|
5857
|
+
return false;
|
|
5858
|
+
}
|
|
5859
|
+
}
|
|
5860
|
+
function ensureInitialized() {
|
|
5861
|
+
if (!isOverlayTelemetryEnabled()) return false;
|
|
5862
|
+
const token = posthogToken();
|
|
5863
|
+
if (!tokenIsConfigured(token)) return false;
|
|
5864
|
+
if (!initialized) {
|
|
5865
|
+
const debug = typeof localStorage !== "undefined" && localStorage.getItem("nuvio.telemetry.debug") === "1";
|
|
5866
|
+
posthog.init(token, {
|
|
5867
|
+
api_host: POSTHOG_HOST,
|
|
5868
|
+
ui_host: "https://us.posthog.com",
|
|
5869
|
+
autocapture: false,
|
|
5870
|
+
capture_pageview: false,
|
|
5871
|
+
disable_session_recording: true,
|
|
5872
|
+
person_profiles: "identified_only",
|
|
5873
|
+
persistence: "localStorage",
|
|
5874
|
+
debug
|
|
5875
|
+
});
|
|
5876
|
+
initialized = true;
|
|
5877
|
+
}
|
|
5878
|
+
return true;
|
|
5879
|
+
}
|
|
5880
|
+
function mapApplyFailureReason(errorCode, options) {
|
|
5881
|
+
if (options?.duplicateIdsActive && errorCode === "unknown_id") {
|
|
5882
|
+
return "duplicate_id";
|
|
5883
|
+
}
|
|
5884
|
+
if (errorCode === "unknown_id" || errorCode === "host_not_found") {
|
|
5885
|
+
return "no_patch_target";
|
|
5886
|
+
}
|
|
5887
|
+
if (errorCode === "patch_rejected") {
|
|
5888
|
+
return "unsupported_classname";
|
|
5889
|
+
}
|
|
5890
|
+
return "apply_error";
|
|
5891
|
+
}
|
|
5892
|
+
function captureOverlayEvent(event, props) {
|
|
5893
|
+
try {
|
|
5894
|
+
if (!ensureInitialized()) return;
|
|
5895
|
+
const payload = {};
|
|
5896
|
+
if (props?.reason) {
|
|
5897
|
+
payload.reason = props.reason;
|
|
5898
|
+
}
|
|
5899
|
+
posthog.capture(event, Object.keys(payload).length > 0 ? payload : void 0);
|
|
5900
|
+
} catch {
|
|
5901
|
+
}
|
|
5902
|
+
}
|
|
5903
|
+
function captureOverlayConnected() {
|
|
5904
|
+
if (overlayConnectedSent) return;
|
|
5905
|
+
overlayConnectedSent = true;
|
|
5906
|
+
captureOverlayEvent("overlay_connected");
|
|
5907
|
+
}
|
|
5908
|
+
function captureFirstSelection() {
|
|
5909
|
+
if (firstSelectionSent) return;
|
|
5910
|
+
firstSelectionSent = true;
|
|
5911
|
+
captureOverlayEvent("first_selection");
|
|
5912
|
+
}
|
|
5913
|
+
function captureApplyFailed(errorCode, options) {
|
|
5914
|
+
captureOverlayEvent("apply_failed", {
|
|
5915
|
+
reason: mapApplyFailureReason(errorCode, options)
|
|
5916
|
+
});
|
|
5917
|
+
}
|
|
5918
|
+
|
|
5696
5919
|
// src/NuvioDevShell.tsx
|
|
5697
5920
|
import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
5698
5921
|
function shortDisplayPath(absPath) {
|
|
@@ -5848,7 +6071,7 @@ function NuvioDevShellInner() {
|
|
|
5848
6071
|
},
|
|
5849
6072
|
onDragEnd: commitChipDrag
|
|
5850
6073
|
});
|
|
5851
|
-
|
|
6074
|
+
useLayoutEffect3(() => {
|
|
5852
6075
|
if (chipDragging) {
|
|
5853
6076
|
return;
|
|
5854
6077
|
}
|
|
@@ -5887,7 +6110,7 @@ function NuvioDevShellInner() {
|
|
|
5887
6110
|
chromeLayout.panel.position,
|
|
5888
6111
|
onPanelPositionChange
|
|
5889
6112
|
]);
|
|
5890
|
-
|
|
6113
|
+
useLayoutEffect3(() => {
|
|
5891
6114
|
const panelPos = chromeLayout.panel.position;
|
|
5892
6115
|
if (!panelPos || !panelRef.current) {
|
|
5893
6116
|
return;
|
|
@@ -5904,7 +6127,7 @@ function NuvioDevShellInner() {
|
|
|
5904
6127
|
onPanelPositionChange(clamped);
|
|
5905
6128
|
}
|
|
5906
6129
|
}, [chromeLayout.panel.position, onPanelPositionChange]);
|
|
5907
|
-
|
|
6130
|
+
useLayoutEffect3(() => {
|
|
5908
6131
|
if (!chipPos || !chipRef.current || chipDragging) {
|
|
5909
6132
|
return;
|
|
5910
6133
|
}
|
|
@@ -5949,6 +6172,7 @@ function NuvioDevShellInner() {
|
|
|
5949
6172
|
const resolvedFileRef = useRef5(void 0);
|
|
5950
6173
|
const selectedIdRef = useRef5(null);
|
|
5951
6174
|
const lastIndexEntriesRef = useRef5([]);
|
|
6175
|
+
const duplicateErrorsRef = useRef5([]);
|
|
5952
6176
|
const lastStagedOpsFpRef = useRef5(null);
|
|
5953
6177
|
const autoApplyStructuralRef = useRef5(false);
|
|
5954
6178
|
const [structuralPreviewActive, setStructuralPreviewActive] = useState9(false);
|
|
@@ -5958,6 +6182,9 @@ function NuvioDevShellInner() {
|
|
|
5958
6182
|
useEffect9(() => {
|
|
5959
6183
|
selectedIdRef.current = selectedId;
|
|
5960
6184
|
}, [selectedId]);
|
|
6185
|
+
useEffect9(() => {
|
|
6186
|
+
duplicateErrorsRef.current = duplicateErrors;
|
|
6187
|
+
}, [duplicateErrors]);
|
|
5961
6188
|
const selectedEntry = useMemo6(
|
|
5962
6189
|
() => selectedId ? indexEntries.find((e) => e.id === selectedId) : void 0,
|
|
5963
6190
|
[indexEntries, selectedId]
|
|
@@ -5988,7 +6215,7 @@ function NuvioDevShellInner() {
|
|
|
5988
6215
|
if (dryRun) {
|
|
5989
6216
|
setPreviewBusy(false);
|
|
5990
6217
|
setPreviewError(
|
|
5991
|
-
!ws || ws.readyState !== WebSocket.OPEN ? "Dev channel is not connected \u2014 wait for \u201Cconnected\u201D in the chip, then try
|
|
6218
|
+
!ws || ws.readyState !== WebSocket.OPEN ? "Dev channel is not connected \u2014 wait for \u201Cconnected\u201D in the chip, then try Preview Changes again." : "Nothing is selected \u2014 click an element on the page first."
|
|
5992
6219
|
);
|
|
5993
6220
|
} else {
|
|
5994
6221
|
setLastPatchError(
|
|
@@ -6016,7 +6243,7 @@ function NuvioDevShellInner() {
|
|
|
6016
6243
|
}
|
|
6017
6244
|
patchPendingMapRef.current.delete(requestId);
|
|
6018
6245
|
setPreviewBusy(false);
|
|
6019
|
-
setPreviewError("No validation response from the dev server (timed out). Check the terminal for [
|
|
6246
|
+
setPreviewError("No validation response from the dev server (timed out). Check the terminal for [nuvio] errors.");
|
|
6020
6247
|
}, 15e3);
|
|
6021
6248
|
}
|
|
6022
6249
|
ws.send(
|
|
@@ -6065,7 +6292,7 @@ function NuvioDevShellInner() {
|
|
|
6065
6292
|
const fp = JSON.stringify(ops);
|
|
6066
6293
|
if (fp !== previewValidatedFingerprint) {
|
|
6067
6294
|
setLastPatchError(
|
|
6068
|
-
"Run
|
|
6295
|
+
"Run Preview Changes first \u2014 staged edits changed since the last successful preview."
|
|
6069
6296
|
);
|
|
6070
6297
|
return;
|
|
6071
6298
|
}
|
|
@@ -6151,6 +6378,7 @@ function NuvioDevShellInner() {
|
|
|
6151
6378
|
setLastPatchError(null);
|
|
6152
6379
|
setSelectedId(id);
|
|
6153
6380
|
setSelectError(null);
|
|
6381
|
+
captureFirstSelection();
|
|
6154
6382
|
const hit = lastIndexEntriesRef.current.find((e) => e.id === id);
|
|
6155
6383
|
if (hit) {
|
|
6156
6384
|
setResolvedFile(shortDisplayPath(hit.file));
|
|
@@ -6184,6 +6412,7 @@ function NuvioDevShellInner() {
|
|
|
6184
6412
|
}
|
|
6185
6413
|
retryMs = 400;
|
|
6186
6414
|
setChannel("ready");
|
|
6415
|
+
captureOverlayConnected();
|
|
6187
6416
|
patchPendingMapRef.current.clear();
|
|
6188
6417
|
if (previewTimeoutRef.current) {
|
|
6189
6418
|
clearTimeout(previewTimeoutRef.current);
|
|
@@ -6284,6 +6513,7 @@ function NuvioDevShellInner() {
|
|
|
6284
6513
|
setPreviewError(null);
|
|
6285
6514
|
setPreviewValidatedFingerprint(savedFp);
|
|
6286
6515
|
setPreviewValidatedOps(pending.ops);
|
|
6516
|
+
captureOverlayEvent("preview_changes");
|
|
6287
6517
|
if (autoApplyStructuralRef.current && isStructuralOnlyOps(pending.ops)) {
|
|
6288
6518
|
autoApplyStructuralRef.current = false;
|
|
6289
6519
|
sendPatchMessage(
|
|
@@ -6314,8 +6544,12 @@ function NuvioDevShellInner() {
|
|
|
6314
6544
|
if (msg.undoStackDepth !== void 0) {
|
|
6315
6545
|
setUndoStackDepth(msg.undoStackDepth);
|
|
6316
6546
|
}
|
|
6547
|
+
captureOverlayEvent("apply_to_code");
|
|
6317
6548
|
} else {
|
|
6318
6549
|
setLastPatchError(msg.errorMessage ?? msg.errorCode ?? "Apply failed");
|
|
6550
|
+
captureApplyFailed(msg.errorCode, {
|
|
6551
|
+
duplicateIdsActive: duplicateErrorsRef.current.length > 0
|
|
6552
|
+
});
|
|
6319
6553
|
}
|
|
6320
6554
|
return;
|
|
6321
6555
|
}
|
|
@@ -6472,7 +6706,7 @@ function NuvioDevShellInner() {
|
|
|
6472
6706
|
className: `nuvio-chip-header ${chipDragging ? "nuvio-chip-header--grabbing" : ""}`,
|
|
6473
6707
|
onPointerDown: onChipHeaderPointerDown,
|
|
6474
6708
|
children: [
|
|
6475
|
-
/* @__PURE__ */ jsx15("span", { className: "nuvio-chip-title", children: "
|
|
6709
|
+
/* @__PURE__ */ jsx15("span", { className: "nuvio-chip-title", children: "nuvio" }),
|
|
6476
6710
|
/* @__PURE__ */ jsx15("span", { className: "nuvio-chip-spacer", "aria-hidden": "true" }),
|
|
6477
6711
|
/* @__PURE__ */ jsx15(
|
|
6478
6712
|
"button",
|
|
@@ -6480,7 +6714,7 @@ function NuvioDevShellInner() {
|
|
|
6480
6714
|
type: "button",
|
|
6481
6715
|
className: "nuvio-button-icon",
|
|
6482
6716
|
title: chromeLayout.chip.collapsed ? "Expand chip" : "Collapse chip",
|
|
6483
|
-
"aria-label": chromeLayout.chip.collapsed ? "Expand
|
|
6717
|
+
"aria-label": chromeLayout.chip.collapsed ? "Expand nuvio chip" : "Collapse nuvio chip",
|
|
6484
6718
|
onPointerDown: (e) => e.stopPropagation(),
|
|
6485
6719
|
onClick: () => onChipCollapsedChange(!chromeLayout.chip.collapsed),
|
|
6486
6720
|
children: chromeLayout.chip.collapsed ? "+" : "\u2212"
|
|
@@ -6548,7 +6782,7 @@ function NuvioDevShellInner() {
|
|
|
6548
6782
|
suppressTextTargetHints: !developerDetails
|
|
6549
6783
|
}
|
|
6550
6784
|
),
|
|
6551
|
-
shadowMount ?
|
|
6785
|
+
shadowMount ? createPortal2(chromeUi, shadowMount.mount) : chromeUi
|
|
6552
6786
|
] });
|
|
6553
6787
|
}
|
|
6554
6788
|
|
package/dist/style.css
CHANGED
|
@@ -1102,22 +1102,18 @@ select.nuvio-control {
|
|
|
1102
1102
|
}
|
|
1103
1103
|
|
|
1104
1104
|
.nuvio-color-popover {
|
|
1105
|
-
position: absolute;
|
|
1106
|
-
left: 0;
|
|
1107
|
-
right: 0;
|
|
1108
|
-
z-index: 20;
|
|
1109
|
-
margin-top: 4px;
|
|
1110
|
-
max-height: min(20rem, 50vh);
|
|
1111
1105
|
overflow: auto;
|
|
1112
1106
|
border-radius: var(--nuvio-radius-inner);
|
|
1113
1107
|
border: 1px solid var(--nuvio-border-strong);
|
|
1114
|
-
background:
|
|
1115
|
-
-webkit-backdrop-filter: var(--nuvio-inner-blur);
|
|
1116
|
-
backdrop-filter: var(--nuvio-inner-blur);
|
|
1108
|
+
background: rgb(15, 23, 42);
|
|
1117
1109
|
padding: 10px;
|
|
1118
1110
|
box-shadow: 0 28px 80px rgba(0, 0, 0, 0.42);
|
|
1119
1111
|
}
|
|
1120
1112
|
|
|
1113
|
+
.nuvio-color-popover--fixed {
|
|
1114
|
+
pointer-events: auto;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1121
1117
|
.nuvio-color-specials {
|
|
1122
1118
|
display: flex;
|
|
1123
1119
|
flex-wrap: wrap;
|
|
@@ -1247,7 +1243,10 @@ select.nuvio-control {
|
|
|
1247
1243
|
}
|
|
1248
1244
|
|
|
1249
1245
|
.nuvio-card--actions {
|
|
1246
|
+
position: relative;
|
|
1247
|
+
z-index: 1;
|
|
1250
1248
|
border-color: rgba(56, 189, 248, 0.25);
|
|
1249
|
+
background: rgb(15, 23, 42);
|
|
1251
1250
|
}
|
|
1252
1251
|
|
|
1253
1252
|
.nuvio-action-stack {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuvio/overlay",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"description": "Nuvio dev overlay: edit mode, selection, Editor panel, Validate/Apply/Undo against the Vite dev server.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
"react-dom": "^18.3.1 || ^19.0.0"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"
|
|
47
|
+
"posthog-js": "^1.380.1",
|
|
48
|
+
"@nuvio/shared": "0.5.5"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"@types/react": "^19.0.8",
|