diff --git a/package-lock.json b/package-lock.json
index 6b4e0e8..e25e006 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9146,7 +9146,6 @@
"dependencies": {
"@salt-ds/core": "^1.27.1",
"@salt-ds/icons": "^1.11.2",
- "@salt-ds/lab": "^1.0.0-alpha.44",
"@salt-ds/theme": "^1.15.0",
"react": "^18.3.0",
"react-dom": "^18.3.0"
@@ -9159,7 +9158,6 @@
"dependencies": {
"@salt-ds/core": "^1.27.1",
"@salt-ds/icons": "^1.11.2",
- "@salt-ds/lab": "^1.0.0-alpha.44",
"@salt-ds/theme": "^1.15.0",
"papaparse": "^5.4.1",
"react": "^18.3.0",
@@ -12762,7 +12760,6 @@
"requires": {
"@salt-ds/core": "^1.27.1",
"@salt-ds/icons": "^1.11.2",
- "@salt-ds/lab": "^1.0.0-alpha.44",
"@salt-ds/theme": "^1.15.0",
"react": "^18.3.0",
"react-dom": "^18.3.0"
@@ -12773,7 +12770,6 @@
"requires": {
"@salt-ds/core": "^1.27.1",
"@salt-ds/icons": "^1.11.2",
- "@salt-ds/lab": "^1.0.0-alpha.44",
"@salt-ds/theme": "^1.15.0",
"@types/papaparse": "^5.3.8",
"papaparse": "^5.4.1",
diff --git a/packages/copy-manager/ui-src/__tests__/NodeKeyInput.spec.tsx b/packages/copy-manager/ui-src/__tests__/NodeKeyInput.spec.tsx
new file mode 100644
index 0000000..56012ce
--- /dev/null
+++ b/packages/copy-manager/ui-src/__tests__/NodeKeyInput.spec.tsx
@@ -0,0 +1,29 @@
+import { NodeKeyInput } from "../components/NodeKeyInput";
+import { fireEvent, render, screen, waitFor } from "@testing-library/react";
+import userEvents from "@testing-library/user-event";
+import React from "react";
+import { beforeEach, describe, expect, test, vi } from "vitest";
+import { SelectableTextNodeInfo } from "../../shared-src/messages";
+
+describe("NodeKeyInput", () => {
+ test("call onUpdateNodeKey on blur", async () => {
+ const mockNodeInfo = {
+ characters: "a",
+ checked: false,
+ id: "node1:1",
+ key: "key",
+ name: "Frame 1",
+ } satisfies SelectableTextNodeInfo;
+ const updateSpy = vi.fn();
+ render(
+
+ );
+ await userEvents.type(
+ screen.getByPlaceholderText(mockNodeInfo.name),
+ "abc"
+ );
+ expect(updateSpy).not.toBeCalled();
+ fireEvent.blur(screen.getByPlaceholderText(mockNodeInfo.name));
+ expect(updateSpy).toBeCalledWith(mockNodeInfo.id, "keyabc");
+ });
+});
diff --git a/packages/copy-manager/ui-src/components/NodeKeyInput.tsx b/packages/copy-manager/ui-src/components/NodeKeyInput.tsx
index 75feb95..effc88b 100644
--- a/packages/copy-manager/ui-src/components/NodeKeyInput.tsx
+++ b/packages/copy-manager/ui-src/components/NodeKeyInput.tsx
@@ -1,6 +1,5 @@
-import { Button } from "@salt-ds/core";
+import { Button, Input } from "@salt-ds/core";
import { CloseSmallIcon, WarningIcon } from "@salt-ds/icons";
-import { Input } from "@salt-ds/lab";
import React from "react";
import { SelectableTextNodeInfo } from "../../shared-src/messages";
@@ -17,7 +16,13 @@ export const NodeKeyInput = ({
// Use `key` to force rerender a new Input when nodeInfo key changes
key={`input-${nodeInfo.key}`}
defaultValue={nodeInfo.key}
- inputProps={{ placeholder: nodeInfo.name }}
+ inputProps={{
+ placeholder: nodeInfo.name,
+ onBlur: (e) => {
+ const updatedValue = e.target.value;
+ onUpdateNodeKey(nodeInfo.id, updatedValue);
+ },
+ }}
endAdornment={
nodeInfo.key ? (