diff --git a/packages/compass-components/src/components/document-list/document.spec.tsx b/packages/compass-components/src/components/document-list/document.spec.tsx
new file mode 100644
index 00000000000..5aab0a0e56c
--- /dev/null
+++ b/packages/compass-components/src/components/document-list/document.spec.tsx
@@ -0,0 +1,122 @@
+import React from 'react';
+import { expect } from 'chai';
+import { render, cleanup, screen, within } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import HadronDocument from 'hadron-document';
+import Document from './document';
+
+describe('Document', function () {
+ let doc: HadronDocument;
+ beforeEach(function () {
+ doc = new HadronDocument({ str: 'abc', num: 123, date: new Date(0) });
+ });
+
+ afterEach(cleanup);
+
+ it('should render HadronDocument keys and values', function () {
+ render();
+ expect(screen.getByText('str')).to.exist;
+ expect(screen.getByTitle('abc')).to.exist;
+
+ expect(screen.getByText('num')).to.exist;
+ expect(screen.getByTitle('123')).to.exist;
+
+ expect(screen.getByText('date')).to.exist;
+ expect(screen.getByTitle('1970-01-01T00:00:00.000+00:00')).to.exist;
+ });
+
+ describe('edit mode', function () {
+ it('should change element key name on edit', function () {
+ render();
+
+ const el = document.querySelector(
+ `[data-id="${doc.get('str').uuid}"]`
+ );
+ const keyEditor = within(el).getByTestId('hadron-document-key-editor');
+
+ userEvent.clear(keyEditor);
+ userEvent.keyboard('new_name');
+ userEvent.tab();
+
+ expect(screen.getByDisplayValue('new_name')).to.exist;
+
+ expect(doc.get('new_name').key).to.eq('str');
+ expect(doc.get('new_name').currentKey).to.eq('new_name');
+ });
+
+ it('should change element string value on edit', function () {
+ render();
+
+ const el = document.querySelector(
+ `[data-id="${doc.get('str').uuid}"]`
+ );
+
+ const valueEditor = within(el).getByTestId(
+ 'hadron-document-value-editor'
+ );
+
+ userEvent.clear(valueEditor);
+ userEvent.keyboard('bla');
+ userEvent.tab();
+
+ expect(doc.get('str').currentValue).to.eq('bla');
+ expect(doc.get('str').currentType).to.eq('String');
+ });
+
+ it('should change element number value on edit', function () {
+ render();
+
+ const el = document.querySelector(
+ `[data-id="${doc.get('num').uuid}"]`
+ );
+
+ const valueEditor = within(el).getByTestId(
+ 'hadron-document-value-editor'
+ );
+
+ userEvent.clear(valueEditor);
+ userEvent.keyboard('321');
+ userEvent.tab();
+
+ expect(doc.get('num').currentValue.valueOf()).to.eq(321);
+ expect(doc.get('num').currentType).to.eq('Int32');
+ });
+
+ it('should change element date value on edit', function () {
+ render();
+
+ const el = document.querySelector(
+ `[data-id="${doc.get('date').uuid}"]`
+ );
+
+ const valueEditor = within(el).getByTestId(
+ 'hadron-document-value-editor'
+ );
+
+ userEvent.clear(valueEditor);
+ userEvent.keyboard('2000-01-01');
+ userEvent.tab();
+
+ expect((doc.get('date').currentValue as Date).toISOString()).to.eq(
+ '2000-01-01T00:00:00.000Z'
+ );
+ expect(doc.get('date').currentType).to.eq('Date');
+ });
+
+ it('should change element type on edit', function () {
+ render();
+
+ const el = document.querySelector(
+ `[data-id="${doc.get('num').uuid}"]`
+ );
+
+ const typeEditor = within(el).getByTestId('hadron-document-type-editor');
+
+ userEvent.selectOptions(typeEditor, 'String');
+ userEvent.tab();
+
+ expect(doc.get('num').currentValue.valueOf()).to.eq('123');
+ expect(doc.get('num').currentType).to.eq('String');
+ });
+ });
+});
diff --git a/packages/compass-components/src/components/document-list/document.tsx b/packages/compass-components/src/components/document-list/document.tsx
index e253b484f42..01bbb4b710d 100644
--- a/packages/compass-components/src/components/document-list/document.tsx
+++ b/packages/compass-components/src/components/document-list/document.tsx
@@ -57,17 +57,17 @@ const hadronDocument = css({
const HadronDocument: React.FunctionComponent<{
value: HadronDocumentType;
visibleFieldsCount?: number;
- expanded: boolean;
- editable: boolean;
+ expanded?: boolean;
+ editable?: boolean;
+ editing?: boolean;
onEditStart?: () => void;
- editing: boolean;
}> = ({
value: document,
visibleFieldsCount,
- expanded,
- editable,
+ expanded = false,
+ editable = false,
+ editing = false,
onEditStart,
- editing,
}) => {
const { elements } = useHadronDocument(document);
const visibleElements = useMemo(() => {
diff --git a/packages/compass-components/src/components/document-list/element-editors.tsx b/packages/compass-components/src/components/document-list/element-editors.tsx
index 01c2b75df44..f18bb0695c0 100644
--- a/packages/compass-components/src/components/document-list/element-editors.tsx
+++ b/packages/compass-components/src/components/document-list/element-editors.tsx
@@ -158,8 +158,10 @@ export const ValueEditor: React.FunctionComponent<{
valid: boolean;
validationMessage: string | null;
originalValue: TypeCastMap[keyof TypeCastMap];
- onChange(newVal: string): void;
autoFocus?: boolean;
+ onChange(newVal: string): void;
+ onFocus(): void;
+ onBlur(): void;
}> = ({
editing,
onEditStart,
@@ -168,8 +170,10 @@ export const ValueEditor: React.FunctionComponent<{
valid,
validationMessage,
originalValue,
- onChange,
autoFocus,
+ onChange,
+ onFocus,
+ onBlur,
}) => {
const val = String(value);
@@ -230,6 +234,8 @@ export const ValueEditor: React.FunctionComponent<{
onChange={(evt) => {
onChange(evt.currentTarget.value);
}}
+ onFocus={onFocus}
+ onBlur={onBlur}
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus={autoFocus}
className={cx(
@@ -251,6 +257,8 @@ export const ValueEditor: React.FunctionComponent<{
onChange={(evt) => {
onChange(evt.currentTarget.value);
}}
+ onFocus={onFocus}
+ onBlur={onBlur}
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus={autoFocus}
className={cx(
diff --git a/packages/compass-components/src/components/document-list/element.tsx b/packages/compass-components/src/components/document-list/element.tsx
index e7a14190452..cb6c6f195c3 100644
--- a/packages/compass-components/src/components/document-list/element.tsx
+++ b/packages/compass-components/src/components/document-list/element.tsx
@@ -139,6 +139,8 @@ function useHadronElement(el: HadronElementType) {
el.currentType !== 'Array',
valid: isValid,
validationMessage: !isValid ? el.invalidTypeMessage ?? null : null,
+ startEdit: editor.start.bind(editor),
+ completeEdit: editor.complete.bind(editor),
},
type: {
value: el.currentType,
@@ -486,6 +488,12 @@ export const HadronElement: React.FunctionComponent<{
onEditStart={() => {
onEditStart?.(element.uuid, 'value');
}}
+ onFocus={() => {
+ value.startEdit();
+ }}
+ onBlur={() => {
+ value.completeEdit();
+ }}
>
) : (