Fixed bindings

This commit is contained in:
2026-06-01 06:45:41 -04:00
parent 27690c3afa
commit 171b790fa3
3 changed files with 54 additions and 1 deletions

View File

@@ -77,6 +77,7 @@ bool ShaderPackageRegistry::Scan(
return false;
}
std::map<std::string, std::string> customUiTagOwners;
for (const auto& entry : std::filesystem::directory_iterator(shaderRoot))
{
if (!entry.is_directory())
@@ -100,6 +101,21 @@ bool ShaderPackageRegistry::Scan(
continue;
}
if (shaderPackage.ui.enabled)
{
const auto tagOwnerIt = customUiTagOwners.find(shaderPackage.ui.customElementTag);
if (tagOwnerIt != customUiTagOwners.end())
{
packageStatuses.push_back(BuildUnavailableStatus(
manifestPath,
shaderPackage,
"Duplicate shader UI custom element tag '" + shaderPackage.ui.customElementTag +
"' already used by shader '" + tagOwnerIt->second + "'."));
continue;
}
customUiTagOwners[shaderPackage.ui.customElementTag] = shaderPackage.id;
}
packageOrder.push_back(shaderPackage.id);
packageStatuses.push_back(BuildAvailableStatus(shaderPackage));
packagesById[shaderPackage.id] = shaderPackage;

View File

@@ -138,6 +138,38 @@ void TestInvalidUiDefinition()
std::filesystem::remove_all(root);
}
void TestDuplicateCustomUiTags()
{
const std::filesystem::path root = MakeTestRoot();
WriteFile(root / "a" / "ui" / "controls.js", "customElements.define('shared-controls', class extends HTMLElement {});\n");
WriteFile(root / "b" / "ui" / "controls.js", "customElements.define('shared-controls', class extends HTMLElement {});\n");
WriteShaderPackage(root, "a", R"({
"id": "shader-a",
"name": "Shader A",
"ui": { "type": "webComponent", "entry": "ui/controls.js", "tag": "shared-controls" },
"parameters": []
})");
WriteShaderPackage(root, "b", R"({
"id": "shader-b",
"name": "Shader B",
"ui": { "type": "webComponent", "entry": "ui/controls.js", "tag": "shared-controls" },
"parameters": []
})");
ShaderPackageRegistry registry(4);
std::map<std::string, ShaderPackage> packages;
std::vector<std::string> order;
std::vector<ShaderPackageStatus> statuses;
std::string error;
Expect(registry.Scan(root, packages, order, statuses, error), "duplicate custom UI tags do not fail the whole scan");
Expect(packages.size() == 1, "only one duplicate custom UI tag owner remains available");
Expect(std::any_of(statuses.begin(), statuses.end(), [](const ShaderPackageStatus& status) {
return !status.available && status.error.find("Duplicate shader UI custom element tag") != std::string::npos;
}), "duplicate custom UI tag is surfaced as an unavailable shader");
std::filesystem::remove_all(root);
}
void TestExplicitPassManifest()
{
const std::filesystem::path root = MakeTestRoot();
@@ -335,6 +367,7 @@ int main()
TestValidManifest();
TestExplicitPassManifest();
TestInvalidUiDefinition();
TestDuplicateCustomUiTags();
TestMissingFontAsset();
TestInvalidManifest();
TestInvalidTemporalSettings();

View File

@@ -140,7 +140,11 @@ export function ShaderCustomPanel({ layer, ui, onParameterChange, onResetParamet
return;
}
if (element.parentNode !== node) {
node.replaceChildren(element);
try {
node.replaceChildren(element);
} catch (error) {
setLoadError(error instanceof Error ? error.message : "Custom controls failed to mount.");
}
}
}}
>