diff --git a/src/components/inline_edit/__snapshots__/inline_edit_title.test.tsx.snap b/src/components/inline_edit/__snapshots__/inline_edit_title.test.tsx.snap
index 58527fff8f8..a83ab3666a5 100644
--- a/src/components/inline_edit/__snapshots__/inline_edit_title.test.tsx.snap
+++ b/src/components/inline_edit/__snapshots__/inline_edit_title.test.tsx.snap
@@ -1,12 +1,48 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`EuiInlineEditTitle isReadOnly 1`] = `
+
+
+
+
+
+ Hello World!
+
+
+
+
+
+ Click this button to edit this text inline.
+
+
+`;
+
exports[`EuiInlineEditTitle renders 1`] = `
@@ -44,7 +80,7 @@ exports[`EuiInlineEditTitle title sizes renders size l 1`] = `
>
@@ -82,7 +118,7 @@ exports[`EuiInlineEditTitle title sizes renders size m 1`] = `
>
@@ -120,7 +156,7 @@ exports[`EuiInlineEditTitle title sizes renders size s 1`] = `
>
@@ -158,7 +194,7 @@ exports[`EuiInlineEditTitle title sizes renders size xs 1`] = `
>
@@ -196,7 +232,7 @@ exports[`EuiInlineEditTitle title sizes renders size xxs 1`] = `
>
@@ -234,7 +270,7 @@ exports[`EuiInlineEditTitle title sizes renders size xxxs 1`] = `
>
diff --git a/src/components/inline_edit/inline_edit_form.styles.ts b/src/components/inline_edit/inline_edit_form.styles.ts
new file mode 100644
index 00000000000..15baae937a3
--- /dev/null
+++ b/src/components/inline_edit/inline_edit_form.styles.ts
@@ -0,0 +1,26 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { css } from '@emotion/react';
+import { UseEuiTheme } from '../../services';
+
+export const euiInlineEditFormStyles = ({ euiTheme }: UseEuiTheme) => {
+ return {
+ euiInlineEditButton: css``,
+
+ // Override the cursor and allow users to highlight text when read mode is in the read only state
+ // Once EuiEmptyButton has been converted to Emotion, remove this extra selector
+ isReadOnly: css`
+ &.euiButtonEmpty:disabled {
+ cursor: text;
+ color: ${euiTheme.colors.text};
+ user-select: text;
+ }
+ `,
+ };
+};
diff --git a/src/components/inline_edit/inline_edit_form.test.tsx b/src/components/inline_edit/inline_edit_form.test.tsx
index 49c9e7de684..0d133d8aabf 100644
--- a/src/components/inline_edit/inline_edit_form.test.tsx
+++ b/src/components/inline_edit/inline_edit_form.test.tsx
@@ -36,6 +36,20 @@ describe('EuiInlineEditForm', () => {
expect(container.firstChild).toMatchSnapshot();
});
+ test('isReadOnly', () => {
+ const { container, getByTestSubject } = render(
+
+ );
+
+ expect(container.firstChild).toMatchSnapshot();
+
+ expect(getByTestSubject('euiInlineReadModeButton')).toBeDisabled();
+ });
+
test('readModeProps', () => {
const { container, getByTestSubject } = render(
&
@@ -80,6 +82,10 @@ export type EuiInlineEditCommonProps = HTMLAttributes &
* Invalid state - only displayed edit mode
*/
isInvalid?: boolean;
+ /**
+ * Locks inline edit in read mode and displays the text value
+ */
+ isReadOnly?: boolean;
};
// Internal-only props, passed by the consumer-facing components
@@ -122,10 +128,18 @@ export const EuiInlineEditForm: FunctionComponent = ({
isLoading = false,
isInvalid,
onSave,
+ isReadOnly,
}) => {
const classes = classNames('euiInlineEdit', className);
const euiTheme = useEuiTheme();
+
+ const styles = euiInlineEditFormStyles(euiTheme);
+ const readOnlyStyles = [
+ styles.euiInlineEditButton,
+ isReadOnly && styles.isReadOnly,
+ ];
+
const { controlHeight, controlCompressedHeight } = euiFormVariables(euiTheme);
const loadingSkeletonSize = sizes.compressed
? controlCompressedHeight
@@ -195,6 +209,13 @@ export const EuiInlineEditForm: FunctionComponent = ({
}
};
+ // If the state of isReadOnly changes while in edit mode, switch back to read mode
+ useEffect(() => {
+ if (isReadOnly) {
+ setIsEditing(false);
+ }
+ }, [isReadOnly]);
+
const editModeForm = (
@@ -228,11 +249,14 @@ export const EuiInlineEditForm: FunctionComponent = ({
)}
/>
+
-
+ {!isReadOnly && (
+
+ )}
@@ -296,12 +320,14 @@ export const EuiInlineEditForm: FunctionComponent = ({
<>
{
expect(container.firstChild).toMatchSnapshot();
});
+ test('isReadOnly', () => {
+ const { container, getByTestSubject } = render(
+
+ );
+
+ expect(container.firstChild).toMatchSnapshot();
+
+ expect(getByTestSubject('euiInlineReadModeButton')).toHaveAttribute(
+ 'role',
+ 'paragraph'
+ );
+ });
+
describe('text sizes', () => {
// Remove 'relative' from text sizes available for EuiInlineEditText
const availableTextSizes = TEXT_SIZES.filter((size) => size !== 'relative');
diff --git a/src/components/inline_edit/inline_edit_text.tsx b/src/components/inline_edit/inline_edit_text.tsx
index 49921fd6d83..8015b7ac141 100644
--- a/src/components/inline_edit/inline_edit_text.tsx
+++ b/src/components/inline_edit/inline_edit_text.tsx
@@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
-import React, { FunctionComponent } from 'react';
+import React, { useMemo, FunctionComponent } from 'react';
import classNames from 'classnames';
import { EuiText, EuiTextProps } from '../text';
import {
@@ -34,10 +34,11 @@ export const EuiInlineEditText: FunctionComponent = ({
defaultValue,
inputAriaLabel,
startWithEditOpen,
- readModeProps,
+ readModeProps: _readModeProps,
editModeProps,
isLoading,
isInvalid,
+ isReadOnly,
...rest
}) => {
const classes = classNames('euiInlineEditText', className);
@@ -49,6 +50,15 @@ export const EuiInlineEditText: FunctionComponent = ({
const isSmallSize = ['xs', 's'].includes(size);
const sizes = isSmallSize ? SMALL_SIZE_FORM : MEDIUM_SIZE_FORM;
+ const readModeProps = useMemo(() => {
+ if (!isReadOnly) return _readModeProps;
+
+ return {
+ ..._readModeProps,
+ role: 'paragraph',
+ };
+ }, [_readModeProps, isReadOnly]);
+
const formProps = {
sizes,
defaultValue,
@@ -58,6 +68,7 @@ export const EuiInlineEditText: FunctionComponent = ({
editModeProps,
isLoading,
isInvalid,
+ isReadOnly,
};
return (
diff --git a/src/components/inline_edit/inline_edit_title.test.tsx b/src/components/inline_edit/inline_edit_title.test.tsx
index 84363d4fd11..6de83071e6c 100644
--- a/src/components/inline_edit/inline_edit_title.test.tsx
+++ b/src/components/inline_edit/inline_edit_title.test.tsx
@@ -39,6 +39,23 @@ describe('EuiInlineEditTitle', () => {
expect(container.querySelector('h3')).toBeTruthy();
});
+ test('isReadOnly', () => {
+ const { container, getByTestSubject } = render(
+
+ );
+
+ expect(container.firstChild).toMatchSnapshot();
+
+ expect(getByTestSubject('euiInlineReadModeButton')).toHaveAttribute(
+ 'role',
+ 'heading'
+ );
+ expect(getByTestSubject('euiInlineReadModeButton')).toHaveAttribute(
+ 'aria-level',
+ '1'
+ );
+ });
+
describe('title sizes', () => {
TITLE_SIZES.forEach((size) => {
it(`renders size ${size}`, () => {
diff --git a/src/components/inline_edit/inline_edit_title.tsx b/src/components/inline_edit/inline_edit_title.tsx
index 6f9d3d0b1d4..451cd1a4697 100644
--- a/src/components/inline_edit/inline_edit_title.tsx
+++ b/src/components/inline_edit/inline_edit_title.tsx
@@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
-import React, { FunctionComponent } from 'react';
+import React, { useMemo, FunctionComponent } from 'react';
import classNames from 'classnames';
import { EuiTitle, EuiTitleSize } from '../title';
import {
@@ -41,10 +41,11 @@ export const EuiInlineEditTitle: FunctionComponent = ({
defaultValue,
inputAriaLabel,
startWithEditOpen,
- readModeProps,
+ readModeProps: _readModeProps,
editModeProps,
isLoading,
isInvalid,
+ isReadOnly,
...rest
}) => {
const classes = classNames('euiInlineEditTitle', className);
@@ -58,6 +59,22 @@ export const EuiInlineEditTitle: FunctionComponent = ({
const isSmallSize = ['xxxs', 'xxs', 'xs', 's'].includes(size);
const sizes = isSmallSize ? SMALL_SIZE_FORM : MEDIUM_SIZE_FORM;
+ const readModeProps = useMemo(() => {
+ if (!isReadOnly) return _readModeProps;
+
+ const headingNumber = Number(heading.substring(1));
+ return headingNumber
+ ? {
+ ..._readModeProps,
+ role: 'heading',
+ 'aria-level': headingNumber,
+ }
+ : {
+ ..._readModeProps,
+ role: 'paragraph',
+ };
+ }, [_readModeProps, isReadOnly, heading]);
+
const formProps = {
sizes,
defaultValue,
@@ -67,6 +84,7 @@ export const EuiInlineEditTitle: FunctionComponent = ({
editModeProps,
isLoading,
isInvalid,
+ isReadOnly,
};
return (