@ggui-ai/ui-visual-tester 0.24.0 → 0.26.0
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/README.md +1 -1
- package/fixture/fixture-runtime.js +118 -38
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @ggui-ai/ui-visual-tester
|
|
2
2
|
|
|
3
|
-
Behavioral validator for [
|
|
3
|
+
Behavioral validator for [GGUI](https://ggui.ai)-generated component code.
|
|
4
4
|
|
|
5
5
|
Structural validators (schema checks, wire-preservation, compile/lint)
|
|
6
6
|
confirm that a component is _shaped_ correctly. They cannot tell you
|
|
@@ -20121,7 +20121,7 @@
|
|
|
20121
20121
|
const inkAlias = "--ggui-surface-" + name + "-ink";
|
|
20122
20122
|
const B = "var(" + bgAlias + ")";
|
|
20123
20123
|
const I = "var(" + inkAlias + ")";
|
|
20124
|
-
return `.${cls}{${bgAlias}:${bg};${inkAlias}:${ink};--ggui-color-onInverted:${ink}}.${cls}>*{--ggui-color-container:${B};--ggui-color-onContainer:${I};--ggui-color-elevated:${B};--ggui-color-onElevated:${I};--ggui-color-sunken:${B};--ggui-color-onSunken:${I};--ggui-color-neutral-500:${I};--ggui-color-ground:${B};--ggui-color-onGround:${I};--ggui-color-link:${accent}}@supports (color: color-mix(in srgb, red, blue)){.${cls}>*{--ggui-color-container:color-mix(in srgb, ${B} 94%, ${I});--ggui-color-elevated:color-mix(in srgb, ${B} 92%, ${I});--ggui-color-sunken:color-mix(in srgb, ${B} 88%, ${I});--ggui-color-onSunken:color-mix(in srgb, ${I} 76%, ${B});--ggui-color-neutral-500:color-mix(in srgb, ${I} 62%, ${B});--ggui-color-outline:${outlineOpen}color-mix(in srgb, ${I} 32%, ${B}));--ggui-color-outlineVariant:color-mix(in srgb, ${I} 18%, ${B})}}`;
|
|
20124
|
+
return `.${cls}{${bgAlias}:${bg};${inkAlias}:${ink};--ggui-color-onInverted:${ink}}.${cls}>*{--ggui-color-container:${B};--ggui-color-onContainer:${I};--ggui-color-elevated:${B};--ggui-color-onElevated:${I};--ggui-color-sunken:${B};--ggui-color-onSunken:${I};--ggui-color-neutral-500:${I};--ggui-color-ground:${B};--ggui-color-onGround:${I};--ggui-color-link:${accent};--ggui-color-controlAccentOutline:${accent}}@supports (color: color-mix(in srgb, red, blue)){.${cls}>*{--ggui-color-container:color-mix(in srgb, ${B} 94%, ${I});--ggui-color-elevated:color-mix(in srgb, ${B} 92%, ${I});--ggui-color-sunken:color-mix(in srgb, ${B} 88%, ${I});--ggui-color-onSunken:color-mix(in srgb, ${I} 76%, ${B});--ggui-color-neutral-500:color-mix(in srgb, ${I} 62%, ${B});--ggui-color-outline:${outlineOpen}color-mix(in srgb, ${I} 32%, ${B}));--ggui-color-controlOutline:${outlineOpen}color-mix(in srgb, ${I} 32%, ${B}));--ggui-color-outlineVariant:color-mix(in srgb, ${I} 18%, ${B})}}`;
|
|
20125
20125
|
}
|
|
20126
20126
|
var INVERTED_SCOPE_CSS = surfaceScopeCss(
|
|
20127
20127
|
INVERTED_SCOPE_CLASS,
|
|
@@ -20657,7 +20657,8 @@
|
|
|
20657
20657
|
},
|
|
20658
20658
|
secondary: {
|
|
20659
20659
|
backgroundColor: "var(--ggui-color-sunken, #f4f4f5)",
|
|
20660
|
-
|
|
20660
|
+
// The label reads at full strength; the chip marks the rank (ggui#1566).
|
|
20661
|
+
color: "var(--ggui-color-onContainer, #18181b)",
|
|
20661
20662
|
border: "none"
|
|
20662
20663
|
},
|
|
20663
20664
|
outline: {
|
|
@@ -20666,13 +20667,15 @@
|
|
|
20666
20667
|
// label is the surface's own on-colour, never a brand-ladder stop
|
|
20667
20668
|
// (ggui#1034): `primary-600` as the label read mid-grey on a monochrome
|
|
20668
20669
|
// dark theme's ground — 2.41:1 / 3.5:1 on served reply chips. The brand
|
|
20669
|
-
// stays on the border,
|
|
20670
|
+
// stays on the border, and the border identifies the control, so it is the
|
|
20671
|
+
// first brand stop that clears 3:1 on the container (ggui#1494).
|
|
20670
20672
|
color: "var(--ggui-color-onContainer, #18181b)",
|
|
20671
|
-
border: "1px solid var(--ggui-color-primary-600, #0284c7)"
|
|
20673
|
+
border: "1px solid var(--ggui-color-controlAccentOutline, var(--ggui-color-primary-600, #0284c7))"
|
|
20672
20674
|
},
|
|
20673
20675
|
ghost: {
|
|
20674
20676
|
backgroundColor: "transparent",
|
|
20675
|
-
|
|
20677
|
+
// A dimmed label reads as disabled; ghost's rank is its missing chrome (ggui#1566).
|
|
20678
|
+
color: "var(--ggui-color-onContainer, #18181b)",
|
|
20676
20679
|
border: "none"
|
|
20677
20680
|
},
|
|
20678
20681
|
danger: {
|
|
@@ -20738,7 +20741,7 @@
|
|
|
20738
20741
|
...sizeStyles2[size],
|
|
20739
20742
|
width: "100%",
|
|
20740
20743
|
borderRadius: "var(--ggui-shape-radius-control, var(--ggui-shape-radius-md, 8px))",
|
|
20741
|
-
border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-outline, #d4d4d8)"}`,
|
|
20744
|
+
border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))"}`,
|
|
20742
20745
|
backgroundColor: disabled ? "var(--ggui-color-sunken, #fafafa)" : "var(--ggui-color-sunken, #ffffff)",
|
|
20743
20746
|
color: "var(--ggui-color-onContainer, #18181b)",
|
|
20744
20747
|
transition: `border-color ${motionVar.duration.base} ${motionVar.easing.standard}, box-shadow ${motionVar.duration.base} ${motionVar.easing.standard}`,
|
|
@@ -20772,7 +20775,7 @@
|
|
|
20772
20775
|
padding: "10px 12px",
|
|
20773
20776
|
width: "100%",
|
|
20774
20777
|
borderRadius: "var(--ggui-shape-radius-control, var(--ggui-shape-radius-md, 8px))",
|
|
20775
|
-
border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-outline, #d4d4d8)"}`,
|
|
20778
|
+
border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))"}`,
|
|
20776
20779
|
backgroundColor: disabled ? "var(--ggui-color-sunken, #fafafa)" : "var(--ggui-color-sunken, #ffffff)",
|
|
20777
20780
|
color: "var(--ggui-color-onContainer, #18181b)",
|
|
20778
20781
|
fontSize: "var(--ggui-font-size-sm, 14px)",
|
|
@@ -20804,17 +20807,25 @@
|
|
|
20804
20807
|
const messageId = `${uniqueId}-message`;
|
|
20805
20808
|
const hasError = Boolean(error);
|
|
20806
20809
|
const hasMessage = Boolean(error || helperText);
|
|
20810
|
+
const startsOnPlaceholder = Boolean(placeholder) && value === void 0 && rest.defaultValue === void 0;
|
|
20811
|
+
const [uncontrolledValue, setUncontrolledValue] = (0, import_react7.useState)(startsOnPlaceholder ? "" : typeof rest.defaultValue === "string" ? rest.defaultValue : void 0);
|
|
20812
|
+
const showingPlaceholder = Boolean(placeholder) && (value ?? uncontrolledValue) === "";
|
|
20807
20813
|
return (0, import_jsx_runtime11.jsxs)("div", { className, style: { display: "flex", flexDirection: "column", gap: "var(--ggui-spacing-1, 4px)", ...style }, children: [label && (0, import_jsx_runtime11.jsxs)("label", { htmlFor: selectId, style: {
|
|
20808
20814
|
fontSize: "var(--ggui-font-size-sm, 14px)",
|
|
20809
20815
|
fontWeight: "var(--ggui-font-weight-medium, 500)",
|
|
20810
20816
|
color: "var(--ggui-color-onSunken, #52525b)"
|
|
20811
|
-
}, children: [label, required && (0, import_jsx_runtime11.jsx)("span", { "aria-hidden": "true", style: { color: "var(--ggui-color-error-500, #ef4444)", marginLeft: "2px" }, children: "*" })] }), (0, import_jsx_runtime11.jsxs)("select", { id: selectId, value,
|
|
20817
|
+
}, children: [label, required && (0, import_jsx_runtime11.jsx)("span", { "aria-hidden": "true", style: { color: "var(--ggui-color-error-500, #ef4444)", marginLeft: "2px" }, children: "*" })] }), (0, import_jsx_runtime11.jsxs)("select", { id: selectId, value, ...startsOnPlaceholder ? { defaultValue: "" } : {}, onChange: (e) => {
|
|
20818
|
+
if (value === void 0)
|
|
20819
|
+
setUncontrolledValue(e.target.value);
|
|
20820
|
+
onChange?.(e.target.value);
|
|
20821
|
+
}, disabled, required, "aria-invalid": hasError || void 0, "aria-describedby": hasMessage ? messageId : void 0, style: {
|
|
20812
20822
|
...sizeStyles3[size],
|
|
20813
20823
|
width: "100%",
|
|
20814
20824
|
borderRadius: "var(--ggui-shape-radius-control, var(--ggui-shape-radius-md, 8px))",
|
|
20815
|
-
border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-outline, #d4d4d8)"}`,
|
|
20825
|
+
border: `1px solid ${hasError ? "var(--ggui-color-error-500, #ef4444)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))"}`,
|
|
20816
20826
|
backgroundColor: disabled ? "var(--ggui-color-sunken, #fafafa)" : "var(--ggui-color-sunken, #ffffff)",
|
|
20817
|
-
|
|
20827
|
+
// Muted only while the placeholder is what shows (ggui#1566, #1569).
|
|
20828
|
+
color: showingPlaceholder ? "var(--ggui-color-onSunken, #52525b)" : "var(--ggui-color-onContainer, #18181b)",
|
|
20818
20829
|
cursor: disabled ? "not-allowed" : "pointer",
|
|
20819
20830
|
appearance: "none",
|
|
20820
20831
|
backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M3 4.5L6 7.5L9 4.5'/%3E%3C/svg%3E")`,
|
|
@@ -20859,7 +20870,7 @@
|
|
|
20859
20870
|
width: "18px",
|
|
20860
20871
|
height: "18px",
|
|
20861
20872
|
borderRadius: "var(--ggui-shape-radius-sm, 4px)",
|
|
20862
|
-
border: `2px solid ${checked || indeterminate ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-outline, #d4d4d8)"}`,
|
|
20873
|
+
border: `2px solid ${checked || indeterminate ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))"}`,
|
|
20863
20874
|
backgroundColor: checked || indeterminate ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-sunken, #ffffff)",
|
|
20864
20875
|
display: "flex",
|
|
20865
20876
|
alignItems: "center",
|
|
@@ -20868,7 +20879,7 @@
|
|
|
20868
20879
|
}, children: (checked || indeterminate) && (0, import_jsx_runtime12.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", style: { color: "var(--ggui-color-onPrimary, #ffffff)" }, children: indeterminate ? (0, import_jsx_runtime12.jsx)("path", { d: "M2.5 6H9.5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) : (0, import_jsx_runtime12.jsx)("path", { d: "M2.5 6L5 8.5L9.5 3.5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] }), (label || description) && (0, import_jsx_runtime12.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "2px" }, children: [label && (0, import_jsx_runtime12.jsx)("span", { style: {
|
|
20869
20880
|
fontSize: "var(--ggui-font-size-sm, 14px)",
|
|
20870
20881
|
fontWeight: "var(--ggui-font-weight-medium, 500)",
|
|
20871
|
-
color: "var(--ggui-color-
|
|
20882
|
+
color: "var(--ggui-color-onContainer, #18181b)"
|
|
20872
20883
|
}, children: label }), description && (0, import_jsx_runtime12.jsx)("span", { style: {
|
|
20873
20884
|
fontSize: "var(--ggui-font-size-xs, 12px)",
|
|
20874
20885
|
color: "var(--ggui-color-onSunken, #52525b)"
|
|
@@ -20904,7 +20915,7 @@
|
|
|
20904
20915
|
width: config.width,
|
|
20905
20916
|
height: config.height,
|
|
20906
20917
|
borderRadius: "9999px",
|
|
20907
|
-
backgroundColor: checked ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-outline, #d4d4d8)",
|
|
20918
|
+
backgroundColor: checked ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))",
|
|
20908
20919
|
position: "relative",
|
|
20909
20920
|
transition: `background-color ${motionVar.duration.base} ${motionVar.easing.standard}, box-shadow ${motionVar.duration.base} ${motionVar.easing.standard}`,
|
|
20910
20921
|
flexShrink: 0,
|
|
@@ -20923,7 +20934,7 @@
|
|
|
20923
20934
|
} }) }), label && (0, import_jsx_runtime13.jsx)("span", { style: {
|
|
20924
20935
|
fontSize: "var(--ggui-font-size-sm, 14px)",
|
|
20925
20936
|
fontWeight: "var(--ggui-font-weight-medium, 500)",
|
|
20926
|
-
color: "var(--ggui-color-
|
|
20937
|
+
color: "var(--ggui-color-onContainer, #18181b)"
|
|
20927
20938
|
}, children: label })] });
|
|
20928
20939
|
}
|
|
20929
20940
|
|
|
@@ -20971,7 +20982,7 @@
|
|
|
20971
20982
|
width: "18px",
|
|
20972
20983
|
height: "18px",
|
|
20973
20984
|
borderRadius: "var(--ggui-shape-radius-full, 9999px)",
|
|
20974
|
-
border: `2px solid ${isSelected ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-outline, #d4d4d8)"}`,
|
|
20985
|
+
border: `2px solid ${isSelected ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d4d4d8))"}`,
|
|
20975
20986
|
backgroundColor: "var(--ggui-color-sunken, #ffffff)",
|
|
20976
20987
|
display: "flex",
|
|
20977
20988
|
alignItems: "center",
|
|
@@ -20985,7 +20996,7 @@
|
|
|
20985
20996
|
} }) })] }), (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "2px" }, children: [(0, import_jsx_runtime14.jsx)("span", { style: {
|
|
20986
20997
|
fontSize: "var(--ggui-font-size-sm, 14px)",
|
|
20987
20998
|
fontWeight: "var(--ggui-font-weight-medium, 500)",
|
|
20988
|
-
color: "var(--ggui-color-
|
|
20999
|
+
color: "var(--ggui-color-onContainer, #18181b)"
|
|
20989
21000
|
}, children: option.label }), option.description && (0, import_jsx_runtime14.jsx)("span", { style: {
|
|
20990
21001
|
fontSize: "var(--ggui-font-size-xs, 12px)",
|
|
20991
21002
|
color: "var(--ggui-color-onSunken, #52525b)"
|
|
@@ -26043,7 +26054,9 @@
|
|
|
26043
26054
|
width: "100%",
|
|
26044
26055
|
borderCollapse: "collapse",
|
|
26045
26056
|
fontSize: "var(--ggui-font-size-sm, 14px)",
|
|
26046
|
-
|
|
26057
|
+
// Body cells are the data and inherit this (ggui#1566); the header and
|
|
26058
|
+
// caption set the muted tier themselves.
|
|
26059
|
+
color: "var(--ggui-color-onContainer, #18181b)"
|
|
26047
26060
|
}, children: [caption && (0, import_jsx_runtime25.jsx)("caption", { style: {
|
|
26048
26061
|
padding: cellPadding,
|
|
26049
26062
|
fontSize: "var(--ggui-font-size-sm, 14px)",
|
|
@@ -26509,7 +26522,7 @@
|
|
|
26509
26522
|
}, children: isExpanded && (0, import_jsx_runtime28.jsx)("div", { style: {
|
|
26510
26523
|
padding: "0 var(--ggui-spacing-4, 16px) var(--ggui-spacing-4, 16px)",
|
|
26511
26524
|
fontSize: "var(--ggui-font-size-sm, 14px)",
|
|
26512
|
-
color: "var(--ggui-color-
|
|
26525
|
+
color: "var(--ggui-color-onContainer, #18181b)",
|
|
26513
26526
|
lineHeight: "var(--ggui-font-lineHeight-normal, 1.5)"
|
|
26514
26527
|
}, children: item.content }) })] }, item.key);
|
|
26515
26528
|
}) });
|
|
@@ -26626,7 +26639,7 @@
|
|
|
26626
26639
|
paddingLeft: "36px",
|
|
26627
26640
|
fontSize: size === "lg" ? "16px" : "14px",
|
|
26628
26641
|
borderRadius: "6px",
|
|
26629
|
-
border: `1px solid var(--ggui-color-outline, #d1d5db)`,
|
|
26642
|
+
border: `1px solid var(--ggui-color-controlOutline, var(--ggui-color-outline, #d1d5db))`,
|
|
26630
26643
|
backgroundColor: disabled ? "var(--ggui-color-sunken, #f9fafb)" : "var(--ggui-color-container, #ffffff)",
|
|
26631
26644
|
color: "var(--ggui-color-onContainer, #111827)",
|
|
26632
26645
|
outline: "none",
|
|
@@ -27824,14 +27837,17 @@
|
|
|
27824
27837
|
padding: "10px 14px",
|
|
27825
27838
|
borderRadius: radius.lg,
|
|
27826
27839
|
backgroundColor: isOwn ? "var(--ggui-color-primary-600, #0284c7)" : "var(--ggui-color-sunken, #f3f4f6)",
|
|
27827
|
-
color: isOwn ? "var(--ggui-color-onPrimary, #ffffff)" : "var(--ggui-color-
|
|
27840
|
+
color: isOwn ? "var(--ggui-color-onPrimary, #ffffff)" : "var(--ggui-color-onContainer, #111827)"
|
|
27828
27841
|
}, children: [(0, import_jsx_runtime46.jsx)("p", { style: { margin: 0, fontSize: fontSize.sm }, children: message.content }), (0, import_jsx_runtime46.jsxs)("div", { style: {
|
|
27829
27842
|
display: "flex",
|
|
27830
27843
|
alignItems: "center",
|
|
27831
27844
|
gap: "4px",
|
|
27832
27845
|
marginTop: "4px",
|
|
27833
27846
|
fontSize: fontSize.xs,
|
|
27834
|
-
|
|
27847
|
+
// Own messages derive the muted line from onPrimary; the other
|
|
27848
|
+
// party's message now reads at onContainer, so its timestamp
|
|
27849
|
+
// takes the muted tier itself (ggui#1566).
|
|
27850
|
+
...isOwn ? { opacity: 0.7 } : { color: "var(--ggui-color-onSunken, #52525b)" }
|
|
27835
27851
|
}, children: [(0, import_jsx_runtime46.jsx)("span", { children: timestamp }), isOwn && message.status && (0, import_jsx_runtime46.jsxs)("span", { children: [message.status === "sending" && "\u2022", message.status === "sent" && "\u2713", message.status === "delivered" && "\u2713\u2713", message.status === "read" && "\u2713\u2713", message.status === "error" && "!"] })] })] })] }, message.id);
|
|
27836
27852
|
}), typing && (0, import_jsx_runtime46.jsx)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: (0, import_jsx_runtime46.jsxs)("span", { style: { fontSize: fontSize.xs, color: "var(--ggui-color-neutral-500, #6b7280)" }, children: [typing.name, " is typing..."] }) }), (0, import_jsx_runtime46.jsx)("div", { ref: messagesEndRef })] }), (0, import_jsx_runtime46.jsxs)("div", { style: {
|
|
27837
27853
|
padding: "12px 16px",
|
|
@@ -27841,7 +27857,7 @@
|
|
|
27841
27857
|
}, children: [(0, import_jsx_runtime46.jsx)("input", { type: "text", value: inputValue, onChange: (e) => setInputValue(e.target.value), onKeyDown: handleKeyDown, placeholder, style: {
|
|
27842
27858
|
flex: 1,
|
|
27843
27859
|
padding: "10px 14px",
|
|
27844
|
-
border: `1px solid var(--ggui-color-outline, #d1d5db)`,
|
|
27860
|
+
border: `1px solid var(--ggui-color-controlOutline, var(--ggui-color-outline, #d1d5db))`,
|
|
27845
27861
|
borderRadius: radius.full,
|
|
27846
27862
|
fontSize: fontSize.sm,
|
|
27847
27863
|
outline: "none"
|
|
@@ -27953,7 +27969,7 @@
|
|
|
27953
27969
|
setIsDragOver(false);
|
|
27954
27970
|
};
|
|
27955
27971
|
return (0, import_jsx_runtime48.jsxs)("div", { className, style: { ...style }, children: [(0, import_jsx_runtime48.jsxs)("div", { onClick: () => !disabled && inputRef.current?.click(), onDrop: handleDrop, onDragOver: handleDragOver, onDragLeave: handleDragLeave, style: {
|
|
27956
|
-
border: `2px dashed ${isDragOver ? "var(--ggui-color-primary-400, #38bdf8)" : "var(--ggui-color-outline, #d1d5db)"}`,
|
|
27972
|
+
border: `2px dashed ${isDragOver ? "var(--ggui-color-primary-400, #38bdf8)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d1d5db))"}`,
|
|
27957
27973
|
borderRadius: radius.lg,
|
|
27958
27974
|
padding: "32px",
|
|
27959
27975
|
textAlign: "center",
|
|
@@ -28436,7 +28452,7 @@
|
|
|
28436
28452
|
fontWeight: fontWeight.semibold,
|
|
28437
28453
|
color: showOverlay ? "#ffffff" : "var(--ggui-color-onContainer, #374151)",
|
|
28438
28454
|
backgroundColor: "transparent",
|
|
28439
|
-
border: `1px solid ${showOverlay ? "rgba(255,255,255,0.3)" : "var(--ggui-color-outline, #d1d5db)"}`,
|
|
28455
|
+
border: `1px solid ${showOverlay ? "rgba(255,255,255,0.3)" : "var(--ggui-color-controlOutline, var(--ggui-color-outline, #d1d5db))"}`,
|
|
28440
28456
|
borderRadius: "8px",
|
|
28441
28457
|
cursor: "pointer",
|
|
28442
28458
|
transition: "all 0.15s",
|
|
@@ -28577,6 +28593,7 @@
|
|
|
28577
28593
|
buildWireConfig: () => buildWireConfig,
|
|
28578
28594
|
connectionSource: () => connectionSource,
|
|
28579
28595
|
useAction: () => useAction,
|
|
28596
|
+
useActionPending: () => useActionPending,
|
|
28580
28597
|
useActionSpent: () => useActionSpent,
|
|
28581
28598
|
useApp: () => useApp,
|
|
28582
28599
|
useAuth: () => useAuth,
|
|
@@ -28679,8 +28696,19 @@
|
|
|
28679
28696
|
return (0, import_react35.useSyncExternalStore)(subscribe, read, read);
|
|
28680
28697
|
}
|
|
28681
28698
|
|
|
28682
|
-
// ../wire/dist/
|
|
28699
|
+
// ../wire/dist/action-pending.js
|
|
28683
28700
|
var import_react36 = __toESM(require_react(), 1);
|
|
28701
|
+
var ActionPendingContext = (0, import_react36.createContext)(null);
|
|
28702
|
+
var noSubscription2 = () => () => void 0;
|
|
28703
|
+
function useActionPending(actionName) {
|
|
28704
|
+
const source = (0, import_react36.useContext)(ActionPendingContext);
|
|
28705
|
+
const subscribe = (0, import_react36.useCallback)((listener) => source === null ? noSubscription2() : source.subscribe(listener), [source]);
|
|
28706
|
+
const read = (0, import_react36.useCallback)(() => source === null ? false : source.isPending(actionName), [source, actionName]);
|
|
28707
|
+
return (0, import_react36.useSyncExternalStore)(subscribe, read, read);
|
|
28708
|
+
}
|
|
28709
|
+
|
|
28710
|
+
// ../wire/dist/useGguiContext.js
|
|
28711
|
+
var import_react37 = __toESM(require_react(), 1);
|
|
28684
28712
|
function useGguiContext(slotName) {
|
|
28685
28713
|
const contextName = slotName.length === 0 ? "Context" : slotName.charAt(0).toUpperCase() + slotName.slice(1) + "Context";
|
|
28686
28714
|
const registry = globalThis.__ggui__?.contexts;
|
|
@@ -28688,19 +28716,19 @@
|
|
|
28688
28716
|
if (!ctx) {
|
|
28689
28717
|
throw new Error(`[ggui] useGguiContext('${slotName}'): no Context registered. The contract must declare 'contextSpec.${slotName}' AND the runtime must have synthesized the per-slot React Context at boot. If you see this in production code generated by the LLM, the boilerplate's destructure line drifted from the contract.`);
|
|
28690
28718
|
}
|
|
28691
|
-
return (0,
|
|
28719
|
+
return (0, import_react37.useContext)(ctx);
|
|
28692
28720
|
}
|
|
28693
28721
|
|
|
28694
28722
|
// ../wire/dist/useStream.js
|
|
28695
|
-
var
|
|
28723
|
+
var import_react38 = __toESM(require_react(), 1);
|
|
28696
28724
|
function useStream(channelName) {
|
|
28697
28725
|
const { subscribe } = useWireContext();
|
|
28698
|
-
const [latest, setLatest] = (0,
|
|
28699
|
-
const [all, setAll] = (0,
|
|
28700
|
-
const [isComplete, setIsComplete] = (0,
|
|
28701
|
-
const allRef = (0,
|
|
28726
|
+
const [latest, setLatest] = (0, import_react38.useState)(null);
|
|
28727
|
+
const [all, setAll] = (0, import_react38.useState)([]);
|
|
28728
|
+
const [isComplete, setIsComplete] = (0, import_react38.useState)(false);
|
|
28729
|
+
const allRef = (0, import_react38.useRef)(all);
|
|
28702
28730
|
allRef.current = all;
|
|
28703
|
-
(0,
|
|
28731
|
+
(0, import_react38.useEffect)(() => {
|
|
28704
28732
|
return subscribe(channelName, (delivery) => {
|
|
28705
28733
|
const typed = delivery.payload;
|
|
28706
28734
|
setLatest(typed);
|
|
@@ -28738,7 +28766,7 @@
|
|
|
28738
28766
|
}
|
|
28739
28767
|
|
|
28740
28768
|
// ../wire/dist/useRender.js
|
|
28741
|
-
var
|
|
28769
|
+
var import_react39 = __toESM(require_react(), 1);
|
|
28742
28770
|
|
|
28743
28771
|
// ../wire/dist/connection-store.js
|
|
28744
28772
|
var ConnectionWriterConflictError = class extends Error {
|
|
@@ -28835,7 +28863,7 @@
|
|
|
28835
28863
|
// ../wire/dist/useRender.js
|
|
28836
28864
|
function useRender() {
|
|
28837
28865
|
const { render } = useWireContext();
|
|
28838
|
-
const isConnected = (0,
|
|
28866
|
+
const isConnected = (0, import_react39.useSyncExternalStore)(connectionSource.subscribe, connectionSource.getSnapshot, connectionSource.getSnapshot);
|
|
28839
28867
|
return { sessionId: render.sessionId, isConnected };
|
|
28840
28868
|
}
|
|
28841
28869
|
|
|
@@ -29411,6 +29439,7 @@
|
|
|
29411
29439
|
}
|
|
29412
29440
|
}
|
|
29413
29441
|
};
|
|
29442
|
+
var DEFAULT_ACTION_PENDING_BOUND_MS = 2e4;
|
|
29414
29443
|
function buildWireConfig(opts) {
|
|
29415
29444
|
let internalSeq = 0;
|
|
29416
29445
|
const nextClientSeq = opts.nextClientSeq ?? (() => {
|
|
@@ -29435,8 +29464,43 @@
|
|
|
29435
29464
|
}
|
|
29436
29465
|
};
|
|
29437
29466
|
opts.spentInputsChanged?.(notifySpent);
|
|
29467
|
+
const pendingBoundMs = opts.actionPendingBoundMs ?? DEFAULT_ACTION_PENDING_BOUND_MS;
|
|
29468
|
+
const pending = /* @__PURE__ */ new Map();
|
|
29469
|
+
const pendingListeners = /* @__PURE__ */ new Set();
|
|
29470
|
+
const notifyPending = () => {
|
|
29471
|
+
for (const listener of [...pendingListeners])
|
|
29472
|
+
listener();
|
|
29473
|
+
};
|
|
29474
|
+
const markPending = (actionName) => {
|
|
29475
|
+
const previous = pending.get(actionName);
|
|
29476
|
+
if (previous !== void 0)
|
|
29477
|
+
clearTimeout(previous);
|
|
29478
|
+
pending.set(actionName, setTimeout(() => {
|
|
29479
|
+
pending.delete(actionName);
|
|
29480
|
+
notifyPending();
|
|
29481
|
+
}, pendingBoundMs));
|
|
29482
|
+
notifyPending();
|
|
29483
|
+
};
|
|
29484
|
+
const actionPending = {
|
|
29485
|
+
isPending: (actionName) => pending.has(actionName),
|
|
29486
|
+
subscribe: (listener) => {
|
|
29487
|
+
pendingListeners.add(listener);
|
|
29488
|
+
return () => {
|
|
29489
|
+
pendingListeners.delete(listener);
|
|
29490
|
+
};
|
|
29491
|
+
}
|
|
29492
|
+
};
|
|
29493
|
+
opts.pendingInputsChanged?.(() => {
|
|
29494
|
+
if (pending.size === 0)
|
|
29495
|
+
return;
|
|
29496
|
+
for (const timer of pending.values())
|
|
29497
|
+
clearTimeout(timer);
|
|
29498
|
+
pending.clear();
|
|
29499
|
+
notifyPending();
|
|
29500
|
+
});
|
|
29438
29501
|
return {
|
|
29439
29502
|
actionSpent,
|
|
29503
|
+
actionPending,
|
|
29440
29504
|
app: opts.app,
|
|
29441
29505
|
render: opts.render,
|
|
29442
29506
|
auth: opts.auth,
|
|
@@ -29469,6 +29533,7 @@
|
|
|
29469
29533
|
const result = validateEnvelope(actionSpec, envelope);
|
|
29470
29534
|
if (!result.valid) {
|
|
29471
29535
|
opts.onViolation(new ClientContractViolationError("outbound-action", result.violations));
|
|
29536
|
+
opts.onDispatchRefused?.({ actionName, violations: result.violations });
|
|
29472
29537
|
return;
|
|
29473
29538
|
}
|
|
29474
29539
|
if (isOneShot && !spentOneShots.has(actionName)) {
|
|
@@ -29476,6 +29541,7 @@
|
|
|
29476
29541
|
notifySpent();
|
|
29477
29542
|
}
|
|
29478
29543
|
opts.emitEnvelope(envelope);
|
|
29544
|
+
markPending(actionName);
|
|
29479
29545
|
},
|
|
29480
29546
|
subscribe: (channelName, handler) => {
|
|
29481
29547
|
return opts.streamBus.subscribe(channelName, (env) => {
|
|
@@ -29530,6 +29596,8 @@
|
|
|
29530
29596
|
version: 2,
|
|
29531
29597
|
tokens: [
|
|
29532
29598
|
"--ggui-color-container",
|
|
29599
|
+
"--ggui-color-controlAccentOutline",
|
|
29600
|
+
"--ggui-color-controlOutline",
|
|
29533
29601
|
"--ggui-color-elevated",
|
|
29534
29602
|
"--ggui-color-error",
|
|
29535
29603
|
"--ggui-color-error-100",
|
|
@@ -30161,8 +30229,10 @@
|
|
|
30161
30229
|
// paper
|
|
30162
30230
|
sunken: { $value: "#292929", $type: "color" },
|
|
30163
30231
|
// ink
|
|
30164
|
-
|
|
30165
|
-
//
|
|
30232
|
+
// Muted text, and text on sunken grounds (ggui#1566): the kit's dark muted
|
|
30233
|
+
// value, 6.57:1 on container and 5.80:1 on sunken. Light's onSunken is ink-3,
|
|
30234
|
+
// the same tier, so dark now reads as light already does.
|
|
30235
|
+
onSunken: { $value: "#a3a3a9", $type: "color" },
|
|
30166
30236
|
container: { $value: "#1f1f1f", $type: "color" },
|
|
30167
30237
|
// ink
|
|
30168
30238
|
onContainer: { $value: "#f4f3ed", $type: "color" },
|
|
@@ -32469,12 +32539,18 @@
|
|
|
32469
32539
|
|
|
32470
32540
|
// ../design/dist/themes/ThemeProvider.js
|
|
32471
32541
|
var import_jsx_runtime58 = __toESM(require_jsx_runtime(), 1);
|
|
32472
|
-
var
|
|
32473
|
-
var ThemeContext = (0,
|
|
32542
|
+
var import_react40 = __toESM(require_react(), 1);
|
|
32543
|
+
var ThemeContext = (0, import_react40.createContext)(null);
|
|
32474
32544
|
|
|
32475
32545
|
// ../design/dist/rendering/css-tokens.js
|
|
32476
32546
|
var EXPANDED_FRAME = { outerRadiusVar: "--ggui-shape-radius-xl", insetPx: 16 };
|
|
32477
32547
|
var EXPANDED_FRAME_INNER_RADIUS = `max(0px, calc(var(${EXPANDED_FRAME.outerRadiusVar}) - ${EXPANDED_FRAME.insetPx}px))`;
|
|
32548
|
+
var EXPANDED_FRAME_CHROME = {
|
|
32549
|
+
radius: `var(${EXPANDED_FRAME.outerRadiusVar})`,
|
|
32550
|
+
hairline: "color-mix(in srgb, var(--ggui-color-onGround) 6%, transparent)",
|
|
32551
|
+
shadowVar: "--ggui-shape-shadow-sm",
|
|
32552
|
+
ground: "var(--ggui-color-neutral-50)"
|
|
32553
|
+
};
|
|
32478
32554
|
|
|
32479
32555
|
// ../design/dist/rendering/rewrite-imports.js
|
|
32480
32556
|
var WIRE_EXPORTS = [
|
|
@@ -32494,6 +32570,10 @@
|
|
|
32494
32570
|
// its runtime's shim lacks fails at module link. A card generated to use it
|
|
32495
32571
|
// must never meet a runtime without it.
|
|
32496
32572
|
"useActionSpent",
|
|
32573
|
+
// ggui#1398: whether a dispatched action is waiting for the agent's answer,
|
|
32574
|
+
// as data. Served one release before the triad teaches it, for the same
|
|
32575
|
+
// reason as `useActionSpent` above.
|
|
32576
|
+
"useActionPending",
|
|
32497
32577
|
// Provider component
|
|
32498
32578
|
"GguiWireProvider"
|
|
32499
32579
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ggui-ai/ui-visual-tester",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Behavioral validator for ggui-generated component code. Renders a component in real Chromium via Playwright, clicks each action declared in its contract, and verifies the action actually does something — mutating bound state or dispatching to the agent. Catches buttons wired to no-op handlers that structural validators miss. Playwright is an optional peer dependency, injected by the caller.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ggui",
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"react": "^19.0.0",
|
|
55
55
|
"react-dom": "^19.0.0",
|
|
56
|
-
"@ggui-ai/design": "0.
|
|
57
|
-
"@ggui-ai/
|
|
58
|
-
"@ggui-ai/
|
|
56
|
+
"@ggui-ai/design": "0.26.0",
|
|
57
|
+
"@ggui-ai/wire": "0.26.0",
|
|
58
|
+
"@ggui-ai/protocol": "0.26.0"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@playwright/test": "^1.60.0",
|