diff --git a/.eslintrc.json b/.eslintrc.json
index b23d410..565d182 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -9,6 +9,7 @@
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:@typescript-eslint/recommended",
+ "plugin:react/jsx-runtime",
"prettier"
],
"overrides": [
diff --git a/packages/module/package.json b/packages/module/package.json
index bbc3a3c..e6246f6 100644
--- a/packages/module/package.json
+++ b/packages/module/package.json
@@ -36,8 +36,8 @@
"memoize-one": "^5.1.0"
},
"peerDependencies": {
- "react": "^17 || ^18",
- "react-dom": "^17 || ^18"
+ "react": "^17 || ^18 || ^19",
+ "react-dom": "^17 || ^18 || ^19"
},
"devDependencies": {
"@patternfly/documentation-framework": "^6.0.0-alpha.120",
diff --git a/packages/module/patternfly-docs/content/extensions/react-log-viewer/demos/ComplexToolbarLogViewer.jsx b/packages/module/patternfly-docs/content/extensions/react-log-viewer/demos/ComplexToolbarLogViewer.jsx
index 30eb9d7..610e679 100644
--- a/packages/module/patternfly-docs/content/extensions/react-log-viewer/demos/ComplexToolbarLogViewer.jsx
+++ b/packages/module/patternfly-docs/content/extensions/react-log-viewer/demos/ComplexToolbarLogViewer.jsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import { useState, useRef, useEffect, Fragment } from 'react';
import { data } from '@patternfly/react-log-viewer/patternfly-docs/content/extensions/react-log-viewer/examples/realTestData.js';
import { LogViewer, LogViewerSearch } from '@patternfly/react-log-viewer';
import {
@@ -28,20 +28,20 @@ export const ComplexToolbarLogViewer = () => {
'container-2': { type: 'D', id: 'data2' },
'container-3': { type: 'E', id: 'data3' }
};
- const [isPaused, setIsPaused] = React.useState(false);
- const [isFullScreen, setIsFullScreen] = React.useState(false);
- const [itemCount, setItemCount] = React.useState(1);
- const [currentItemCount, setCurrentItemCount] = React.useState(0);
- const [renderData, setRenderData] = React.useState('');
- const [selectedDataSource, setSelectedDataSource] = React.useState('container-1');
- const [selectDataSourceOpen, setSelectDataSourceOpen] = React.useState(false);
- const [timer, setTimer] = React.useState(null);
- const [selectedData, setSelectedData] = React.useState(data[dataSources[selectedDataSource].id].split('\n'));
- const [buffer, setBuffer] = React.useState([]);
- const [linesBehind, setLinesBehind] = React.useState(0);
- const logViewerRef = React.useRef();
+ const [isPaused, setIsPaused] = useState(false);
+ const [isFullScreen, setIsFullScreen] = useState(false);
+ const [itemCount, setItemCount] = useState(1);
+ const [currentItemCount, setCurrentItemCount] = useState(0);
+ const [renderData, setRenderData] = useState('');
+ const [selectedDataSource, setSelectedDataSource] = useState('container-1');
+ const [selectDataSourceOpen, setSelectDataSourceOpen] = useState(false);
+ const [timer, setTimer] = useState(null);
+ const [selectedData, setSelectedData] = useState(data[dataSources[selectedDataSource].id].split('\n'));
+ const [buffer, setBuffer] = useState([]);
+ const [linesBehind, setLinesBehind] = useState(0);
+ const logViewerRef = useRef(null);
- React.useEffect(() => {
+ useEffect(() => {
setTimer(
window.setInterval(() => {
setItemCount((itemCount) => itemCount + 1);
@@ -52,7 +52,7 @@ export const ComplexToolbarLogViewer = () => {
};
}, []);
- React.useEffect(() => {
+ useEffect(() => {
if (itemCount > selectedData.length) {
window.clearInterval(timer);
} else {
@@ -60,7 +60,7 @@ export const ComplexToolbarLogViewer = () => {
}
}, [itemCount]);
- React.useEffect(() => {
+ useEffect(() => {
if (!isPaused && buffer.length > 0) {
setCurrentItemCount(buffer.length);
setRenderData(buffer.join('\n'));
@@ -75,7 +75,7 @@ export const ComplexToolbarLogViewer = () => {
}, [isPaused, buffer]);
// Listening escape key on full screen mode.
- React.useEffect(() => {
+ useEffect(() => {
const handleFullscreenChange = () => {
const isFullscreen =
document.fullscreenElement ||
@@ -99,7 +99,7 @@ export const ComplexToolbarLogViewer = () => {
};
}, []);
- const onExpandClick = _event => {
+ const onExpandClick = (_event) => {
const element = document.querySelector('#complex-toolbar-demo');
if (!isFullScreen) {
@@ -163,10 +163,10 @@ export const ComplexToolbarLogViewer = () => {
));
const selectDataSourcePlaceholder = (
-
+
{dataSources[selectedDataSource].type}
{` ${selectedDataSource}`}
-
+
);
const ControlButton = () => (
@@ -188,7 +188,7 @@ export const ComplexToolbarLogViewer = () => {
);
const leftAlignedToolbarGroup = (
-
+
} breakpoint="md">
+
);
const rightAlignedToolbarGroup = (
-
+
Download}>
@@ -238,7 +238,7 @@ export const ComplexToolbarLogViewer = () => {
-
+
);
const FooterButton = () => {
diff --git a/packages/module/patternfly-docs/content/extensions/react-log-viewer/demos/LogViewer.md b/packages/module/patternfly-docs/content/extensions/react-log-viewer/demos/LogViewer.md
index 732aed8..9e13540 100644
--- a/packages/module/patternfly-docs/content/extensions/react-log-viewer/demos/LogViewer.md
+++ b/packages/module/patternfly-docs/content/extensions/react-log-viewer/demos/LogViewer.md
@@ -4,6 +4,7 @@ section: extensions
source: react-demos
---
+import { useState, useRef, useEffect, Fragment } from 'react';
import { data } from '@patternfly/react-log-viewer/patternfly-docs/content/extensions/react-log-viewer/examples/realTestData.js';
import { LogViewer, LogViewerSearch } from '@patternfly/react-log-viewer';
import {
@@ -30,4 +31,5 @@ import DownloadIcon from '@patternfly/react-icons/dist/esm/icons/download-icon';
### With complex toolbar
```js file='./ComplexToolbarLogViewer.jsx'
+
```
diff --git a/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/ANSIColorLogViewer.jsx b/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/ANSIColorLogViewer.jsx
index 45eb2d6..774b639 100644
--- a/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/ANSIColorLogViewer.jsx
+++ b/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/ANSIColorLogViewer.jsx
@@ -1,12 +1,6 @@
-import React from 'react';
import { data } from '@patternfly/react-log-viewer/patternfly-docs/content/extensions/react-log-viewer/examples/realTestData.js';
import { LogViewer } from '@patternfly/react-log-viewer';
export const ANSIColorLogViewer = () => (
-
+
);
diff --git a/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/BasicLogViewer.jsx b/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/BasicLogViewer.jsx
index a734776..ceb27b0 100644
--- a/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/BasicLogViewer.jsx
+++ b/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/BasicLogViewer.jsx
@@ -1,13 +1,13 @@
-import React from 'react';
+import { useState, Fragment } from 'react';
import { data } from '@patternfly/react-log-viewer/patternfly-docs/content/extensions/react-log-viewer/examples/realTestData.js';
import { LogViewer } from '@patternfly/react-log-viewer';
import { Checkbox } from '@patternfly/react-core';
export const BasicLogViewer = () => {
- const [isDarkTheme, setIsDarkTheme] = React.useState(false);
+ const [isDarkTheme, setIsDarkTheme] = useState(false);
return (
-
+
{
name="toggle-dark-theme"
/>
-
+
);
};
diff --git a/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/BasicSearchLogViewer.jsx b/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/BasicSearchLogViewer.jsx
index 3437e32..d48477a 100644
--- a/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/BasicSearchLogViewer.jsx
+++ b/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/BasicSearchLogViewer.jsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { data } from '@patternfly/react-log-viewer/patternfly-docs/content/extensions/react-log-viewer/examples/realTestData.js';
import { LogViewer, LogViewerSearch } from '@patternfly/react-log-viewer';
import { Toolbar, ToolbarContent, ToolbarItem } from '@patternfly/react-core';
diff --git a/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/CustomControlLogViewer.jsx b/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/CustomControlLogViewer.jsx
index c7457b4..e5f2b02 100644
--- a/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/CustomControlLogViewer.jsx
+++ b/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/CustomControlLogViewer.jsx
@@ -1,11 +1,11 @@
/* eslint-disable no-console */
-import React from 'react';
+import { useState } from 'react';
import { data } from '@patternfly/react-log-viewer/patternfly-docs/content/extensions/react-log-viewer/examples/realTestData.js';
import { LogViewer, LogViewerSearch } from '@patternfly/react-log-viewer';
import { Toolbar, ToolbarContent, ToolbarItem, Button, Checkbox } from '@patternfly/react-core';
export const CustomControlLogViewer = () => {
- const [isTextWrapped, setIsTextWrapped] = React.useState(false);
+ const [isTextWrapped, setIsTextWrapped] = useState(false);
const onActionClick = () => {
console.log('clicked test action button');
};
@@ -34,8 +34,14 @@ export const CustomControlLogViewer = () => {
Print to Console
-
- setIsTextWrapped(value)} />
+
+ setIsTextWrapped(value)}
+ />
diff --git a/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/FooterComponentLogViewer.jsx b/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/FooterComponentLogViewer.jsx
index d348ed4..bb0c4d9 100644
--- a/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/FooterComponentLogViewer.jsx
+++ b/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/FooterComponentLogViewer.jsx
@@ -1,10 +1,10 @@
-import React from 'react';
+import { useRef } from 'react';
import { data } from '@patternfly/react-log-viewer/patternfly-docs/content/extensions/react-log-viewer/examples/realTestData.js';
import { LogViewer } from '@patternfly/react-log-viewer';
import { Button } from '@patternfly/react-core';
export const FooterComponentLogViewer = () => {
- const logViewerRef = React.useRef();
+ const logViewerRef = useRef(null);
const FooterButton = () => {
const handleClick = () => {
logViewerRef.current.scrollToBottom();
diff --git a/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/HeaderComponentLogViewer.jsx b/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/HeaderComponentLogViewer.jsx
index 4497b24..e97ee5e 100644
--- a/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/HeaderComponentLogViewer.jsx
+++ b/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/HeaderComponentLogViewer.jsx
@@ -1,14 +1,7 @@
-import React from 'react';
import { data } from '@patternfly/react-log-viewer/patternfly-docs/content/extensions/react-log-viewer/examples/realTestData.js';
import { LogViewer } from '@patternfly/react-log-viewer';
import { Banner } from '@patternfly/react-core';
export const HeaderComponentLogViewer = () => (
- 5019 lines}
- />
+ 5019 lines} />
);
diff --git a/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/basic.md b/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/basic.md
index a8236de..ef605d5 100644
--- a/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/basic.md
+++ b/packages/module/patternfly-docs/content/extensions/react-log-viewer/examples/basic.md
@@ -14,6 +14,7 @@ sourceLink: https://github.com/patternfly/react-log-viewer/blob/main/packages/mo
propComponents: [LogViewer, LogViewerSearch]
---
+import { useState, Fragment, useRef } from 'react';
import { LogViewer, LogViewerSearch, LogViewerContext } from '@patternfly/react-log-viewer';
import { Button, Checkbox, Toolbar, ToolbarContent, ToolbarItem } from '@patternfly/react-core';
import { data } from '@patternfly/react-log-viewer/patternfly-docs/content/extensions/react-log-viewer/examples/realTestData.js';
@@ -23,29 +24,35 @@ import { data } from '@patternfly/react-log-viewer/patternfly-docs/content/exten
### Basic
```js file='./BasicLogViewer.jsx'
+
```
### With search
```js file='./BasicSearchLogViewer.jsx'
+
```
### With complex toolbar
```js file='./CustomControlLogViewer.jsx'
+
```
### With header component
```js file='./HeaderComponentLogViewer.jsx'
+
```
### With footer component
```js file='./FooterComponentLogViewer.jsx'
+
```
### With ANSI color logs
```js file='./ANSIColorLogViewer.jsx'
+
```
diff --git a/packages/module/patternfly-docs/generated/extensions/log-viewer/react-demos.js b/packages/module/patternfly-docs/generated/extensions/log-viewer/react-demos.js
index c6b525d..1ec3950 100644
--- a/packages/module/patternfly-docs/generated/extensions/log-viewer/react-demos.js
+++ b/packages/module/patternfly-docs/generated/extensions/log-viewer/react-demos.js
@@ -1,5 +1,6 @@
import React from 'react';
import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components';
+import { useState, useRef, useEffect, Fragment } from 'react';
import { data } from '@patternfly/react-log-viewer/patternfly-docs/content/extensions/react-log-viewer/examples/realTestData.js';
import { LogViewer, LogViewerSearch } from '@patternfly/react-log-viewer';
import {
@@ -41,6 +42,10 @@ const pageData = {
]
};
pageData.liveContext = {
+ useState,
+ useRef,
+ useEffect,
+ Fragment,
data,
LogViewer,
LogViewerSearch,
@@ -65,7 +70,7 @@ pageData.liveContext = {
};
pageData.examples = {
'With complex toolbar': props =>
- {\n const dataSources = {\n 'container-1': { type: 'C', id: 'data1' },\n 'container-2': { type: 'D', id: 'data2' },\n 'container-3': { type: 'E', id: 'data3' }\n };\n const [isPaused, setIsPaused] = React.useState(false);\n const [isFullScreen, setIsFullScreen] = React.useState(false);\n const [itemCount, setItemCount] = React.useState(1);\n const [currentItemCount, setCurrentItemCount] = React.useState(0);\n const [renderData, setRenderData] = React.useState('');\n const [selectedDataSource, setSelectedDataSource] = React.useState('container-1');\n const [selectDataSourceOpen, setSelectDataSourceOpen] = React.useState(false);\n const [timer, setTimer] = React.useState(null);\n const [selectedData, setSelectedData] = React.useState(data[dataSources[selectedDataSource].id].split('\\n'));\n const [buffer, setBuffer] = React.useState([]);\n const [linesBehind, setLinesBehind] = React.useState(0);\n const logViewerRef = React.useRef();\n\n React.useEffect(() => {\n setTimer(\n window.setInterval(() => {\n setItemCount((itemCount) => itemCount + 1);\n }, 500)\n );\n return () => {\n window.clearInterval(timer);\n };\n }, []);\n\n React.useEffect(() => {\n if (itemCount > selectedData.length) {\n window.clearInterval(timer);\n } else {\n setBuffer(selectedData.slice(0, itemCount));\n }\n }, [itemCount]);\n\n React.useEffect(() => {\n if (!isPaused && buffer.length > 0) {\n setCurrentItemCount(buffer.length);\n setRenderData(buffer.join('\\n'));\n if (logViewerRef && logViewerRef.current) {\n logViewerRef.current.scrollToBottom();\n }\n } else if (buffer.length !== currentItemCount) {\n setLinesBehind(buffer.length - currentItemCount);\n } else {\n setLinesBehind(0);\n }\n }, [isPaused, buffer]);\n\n // Listening escape key on full screen mode.\n React.useEffect(() => {\n const handleFullscreenChange = () => {\n const isFullscreen =\n document.fullscreenElement ||\n document.mozFullScreenElement ||\n document.webkitFullscreenElement ||\n document.msFullscreenElement;\n\n setIsFullScreen(!!isFullscreen);\n };\n\n document.addEventListener('fullscreenchange', handleFullscreenChange);\n document.addEventListener('mozfullscreenchange', handleFullscreenChange);\n document.addEventListener('webkitfullscreenchange', handleFullscreenChange);\n document.addEventListener('msfullscreenchange', handleFullscreenChange);\n\n return () => {\n document.removeEventListener('fullscreenchange', handleFullscreenChange);\n document.removeEventListener('mozfullscreenchange', handleFullscreenChange);\n document.removeEventListener('webkitfullscreenchange', handleFullscreenChange);\n document.removeEventListener('msfullscreenchange', handleFullscreenChange);\n };\n }, []);\n\n const onExpandClick = _event => {\n const element = document.querySelector('#complex-toolbar-demo');\n\n if (!isFullScreen) {\n if (element.requestFullscreen) {\n element.requestFullscreen();\n } else if (element.mozRequestFullScreen) {\n element.mozRequestFullScreen();\n } else if (element.webkitRequestFullScreen) {\n element.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);\n }\n setIsFullScreen(true);\n } else {\n if (document.exitFullscreen) {\n document.exitFullscreen();\n } else if (document.webkitExitFullscreen) {\n /* Safari */\n document.webkitExitFullscreen();\n } else if (document.msExitFullscreen) {\n /* IE11 */\n document.msExitFullscreen();\n }\n setIsFullScreen(false);\n }\n };\n\n const onDownloadClick = () => {\n const element = document.createElement('a');\n const dataToDownload = [data[dataSources[selectedDataSource].id]];\n const file = new Blob(dataToDownload, { type: 'text/plain' });\n element.href = URL.createObjectURL(file);\n element.download = `${selectedDataSource}.txt`;\n document.body.appendChild(element);\n element.click();\n document.body.removeChild(element);\n };\n\n const onToggleClick = () => {\n setSelectDataSourceOpen(!selectDataSourceOpen);\n };\n\n const onScroll = ({ scrollOffsetToBottom, _scrollDirection, scrollUpdateWasRequested }) => {\n if (!scrollUpdateWasRequested) {\n if (scrollOffsetToBottom > 0) {\n setIsPaused(true);\n } else {\n setIsPaused(false);\n }\n }\n };\n\n const selectDataSourceMenu = Object.entries(dataSources).map(([value, { type }]) => (\n \n {type}\n {` ${value}`}\n \n ));\n\n const selectDataSourcePlaceholder = (\n \n {dataSources[selectedDataSource].type}\n {` ${selectedDataSource}`}\n \n );\n\n const ControlButton = () => (\n \n );\n\n const toggle = (toggleRef) => (\n \n {selectDataSourcePlaceholder}\n \n );\n\n const leftAlignedToolbarGroup = (\n \n } breakpoint=\"md\">\n \n \n \n \n setIsPaused(true)} placeholder=\"Search\" />\n \n \n \n \n \n \n );\n\n const rightAlignedToolbarGroup = (\n \n \n \n Download}>\n \n \n \n \n Expand}>\n \n \n \n \n \n );\n\n const FooterButton = () => {\n const handleClick = (_e) => {\n setIsPaused(false);\n };\n return (\n \n );\n };\n return (\n \n \n {leftAlignedToolbarGroup}\n {rightAlignedToolbarGroup}\n \n \n }\n overScanCount={10}\n footer={isPaused && }\n onScroll={onScroll}\n />\n );\n};\n","title":"With complex toolbar","lang":"js","className":""}}>
+ {\n const dataSources = {\n 'container-1': { type: 'C', id: 'data1' },\n 'container-2': { type: 'D', id: 'data2' },\n 'container-3': { type: 'E', id: 'data3' }\n };\n const [isPaused, setIsPaused] = useState(false);\n const [isFullScreen, setIsFullScreen] = useState(false);\n const [itemCount, setItemCount] = useState(1);\n const [currentItemCount, setCurrentItemCount] = useState(0);\n const [renderData, setRenderData] = useState('');\n const [selectedDataSource, setSelectedDataSource] = useState('container-1');\n const [selectDataSourceOpen, setSelectDataSourceOpen] = useState(false);\n const [timer, setTimer] = useState(null);\n const [selectedData, setSelectedData] = useState(data[dataSources[selectedDataSource].id].split('\\n'));\n const [buffer, setBuffer] = useState([]);\n const [linesBehind, setLinesBehind] = useState(0);\n const logViewerRef = useRef(null);\n\n useEffect(() => {\n setTimer(\n window.setInterval(() => {\n setItemCount((itemCount) => itemCount + 1);\n }, 500)\n );\n return () => {\n window.clearInterval(timer);\n };\n }, []);\n\n useEffect(() => {\n if (itemCount > selectedData.length) {\n window.clearInterval(timer);\n } else {\n setBuffer(selectedData.slice(0, itemCount));\n }\n }, [itemCount]);\n\n useEffect(() => {\n if (!isPaused && buffer.length > 0) {\n setCurrentItemCount(buffer.length);\n setRenderData(buffer.join('\\n'));\n if (logViewerRef && logViewerRef.current) {\n logViewerRef.current.scrollToBottom();\n }\n } else if (buffer.length !== currentItemCount) {\n setLinesBehind(buffer.length - currentItemCount);\n } else {\n setLinesBehind(0);\n }\n }, [isPaused, buffer]);\n\n // Listening escape key on full screen mode.\n useEffect(() => {\n const handleFullscreenChange = () => {\n const isFullscreen =\n document.fullscreenElement ||\n document.mozFullScreenElement ||\n document.webkitFullscreenElement ||\n document.msFullscreenElement;\n\n setIsFullScreen(!!isFullscreen);\n };\n\n document.addEventListener('fullscreenchange', handleFullscreenChange);\n document.addEventListener('mozfullscreenchange', handleFullscreenChange);\n document.addEventListener('webkitfullscreenchange', handleFullscreenChange);\n document.addEventListener('msfullscreenchange', handleFullscreenChange);\n\n return () => {\n document.removeEventListener('fullscreenchange', handleFullscreenChange);\n document.removeEventListener('mozfullscreenchange', handleFullscreenChange);\n document.removeEventListener('webkitfullscreenchange', handleFullscreenChange);\n document.removeEventListener('msfullscreenchange', handleFullscreenChange);\n };\n }, []);\n\n const onExpandClick = (_event) => {\n const element = document.querySelector('#complex-toolbar-demo');\n\n if (!isFullScreen) {\n if (element.requestFullscreen) {\n element.requestFullscreen();\n } else if (element.mozRequestFullScreen) {\n element.mozRequestFullScreen();\n } else if (element.webkitRequestFullScreen) {\n element.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);\n }\n setIsFullScreen(true);\n } else {\n if (document.exitFullscreen) {\n document.exitFullscreen();\n } else if (document.webkitExitFullscreen) {\n /* Safari */\n document.webkitExitFullscreen();\n } else if (document.msExitFullscreen) {\n /* IE11 */\n document.msExitFullscreen();\n }\n setIsFullScreen(false);\n }\n };\n\n const onDownloadClick = () => {\n const element = document.createElement('a');\n const dataToDownload = [data[dataSources[selectedDataSource].id]];\n const file = new Blob(dataToDownload, { type: 'text/plain' });\n element.href = URL.createObjectURL(file);\n element.download = `${selectedDataSource}.txt`;\n document.body.appendChild(element);\n element.click();\n document.body.removeChild(element);\n };\n\n const onToggleClick = () => {\n setSelectDataSourceOpen(!selectDataSourceOpen);\n };\n\n const onScroll = ({ scrollOffsetToBottom, _scrollDirection, scrollUpdateWasRequested }) => {\n if (!scrollUpdateWasRequested) {\n if (scrollOffsetToBottom > 0) {\n setIsPaused(true);\n } else {\n setIsPaused(false);\n }\n }\n };\n\n const selectDataSourceMenu = Object.entries(dataSources).map(([value, { type }]) => (\n \n {type}\n {` ${value}`}\n \n ));\n\n const selectDataSourcePlaceholder = (\n \n {dataSources[selectedDataSource].type}\n {` ${selectedDataSource}`}\n \n );\n\n const ControlButton = () => (\n \n );\n\n const toggle = (toggleRef) => (\n \n {selectDataSourcePlaceholder}\n \n );\n\n const leftAlignedToolbarGroup = (\n \n } breakpoint=\"md\">\n \n \n \n \n setIsPaused(true)} placeholder=\"Search\" />\n \n \n \n \n \n \n );\n\n const rightAlignedToolbarGroup = (\n \n \n \n Download}>\n \n \n \n \n Expand}>\n \n \n \n \n \n );\n\n const FooterButton = () => {\n const handleClick = (_e) => {\n setIsPaused(false);\n };\n return (\n \n );\n };\n return (\n \n \n {leftAlignedToolbarGroup}\n {rightAlignedToolbarGroup}\n \n \n }\n overScanCount={10}\n footer={isPaused && }\n onScroll={onScroll}\n />\n );\n};\n","title":"With complex toolbar","lang":"js","className":""}}>
};
diff --git a/packages/module/patternfly-docs/generated/extensions/log-viewer/react.js b/packages/module/patternfly-docs/generated/extensions/log-viewer/react.js
index 3dd8640..1d07eec 100644
--- a/packages/module/patternfly-docs/generated/extensions/log-viewer/react.js
+++ b/packages/module/patternfly-docs/generated/extensions/log-viewer/react.js
@@ -1,5 +1,6 @@
import React from 'react';
import { AutoLinkHeader, Example, Link as PatternflyThemeLink } from '@patternfly/documentation-framework/components';
+import { useState, Fragment, useRef } from 'react';
import { LogViewer, LogViewerSearch, LogViewerContext } from '@patternfly/react-log-viewer';
import { Button, Checkbox, Toolbar, ToolbarContent, ToolbarItem } from '@patternfly/react-core';
import { data } from '@patternfly/react-log-viewer/patternfly-docs/content/extensions/react-log-viewer/examples/realTestData.js';
@@ -146,6 +147,9 @@ const pageData = {
]
};
pageData.liveContext = {
+ useState,
+ Fragment,
+ useRef,
LogViewer,
LogViewerSearch,
LogViewerContext,
@@ -158,27 +162,27 @@ pageData.liveContext = {
};
pageData.examples = {
'Basic': props =>
- {\n const [isDarkTheme, setIsDarkTheme] = React.useState(false);\n\n return (\n \n setIsDarkTheme(value)}\n aria-label=\"toggle dark theme checkbox\"\n id=\"toggle-dark-theme\"\n name=\"toggle-dark-theme\"\n />\n \n \n );\n};\n","title":"Basic","lang":"js","className":""}}>
+ {\n const [isDarkTheme, setIsDarkTheme] = useState(false);\n\n return (\n \n setIsDarkTheme(value)}\n aria-label=\"toggle dark theme checkbox\"\n id=\"toggle-dark-theme\"\n name=\"toggle-dark-theme\"\n />\n \n \n );\n};\n","title":"Basic","lang":"js","className":""}}>
,
'With search': props =>
- (\n \n \n \n \n \n \n \n }\n />\n);\n","title":"With search","lang":"js","className":""}}>
+ (\n \n \n \n \n \n \n \n }\n />\n);\n","title":"With search","lang":"js","className":""}}>
,
'With complex toolbar': props =>
- {\n const [isTextWrapped, setIsTextWrapped] = React.useState(false);\n const onActionClick = () => {\n console.log('clicked test action button');\n };\n\n const onPrintClick = () => {\n console.log('clicked console print button');\n };\n\n return (\n \n \n \n \n \n \n \n \n \n \n \n \n setIsTextWrapped(value)} />\n \n \n \n }\n />\n );\n};\n","title":"With complex toolbar","lang":"js","className":""}}>
+ {\n const [isTextWrapped, setIsTextWrapped] = useState(false);\n const onActionClick = () => {\n console.log('clicked test action button');\n };\n\n const onPrintClick = () => {\n console.log('clicked console print button');\n };\n\n return (\n \n \n \n \n \n \n \n \n \n \n \n \n setIsTextWrapped(value)}\n />\n \n \n \n }\n />\n );\n};\n","title":"With complex toolbar","lang":"js","className":""}}>
,
'With header component': props =>
- (\n 5019 lines}\n />\n);\n","title":"With header component","lang":"js","className":""}}>
+ (\n 5019 lines} />\n);\n","title":"With header component","lang":"js","className":""}}>
,
'With footer component': props =>
- {\n const logViewerRef = React.useRef();\n const FooterButton = () => {\n const handleClick = () => {\n logViewerRef.current.scrollToBottom();\n };\n return ;\n };\n\n return (\n }\n />\n );\n};\n","title":"With footer component","lang":"js","className":""}}>
+ {\n const logViewerRef = useRef(null);\n const FooterButton = () => {\n const handleClick = () => {\n logViewerRef.current.scrollToBottom();\n };\n return ;\n };\n\n return (\n }\n />\n );\n};\n","title":"With footer component","lang":"js","className":""}}>
,
'With ANSI color logs': props =>
- (\n \n);\n","title":"With ANSI color logs","lang":"js","className":""}}>
+ (\n \n);\n","title":"With ANSI color logs","lang":"js","className":""}}>
};
diff --git a/packages/module/patternfly-docs/pages/index.js b/packages/module/patternfly-docs/pages/index.js
index 404074c..c2223a3 100644
--- a/packages/module/patternfly-docs/pages/index.js
+++ b/packages/module/patternfly-docs/pages/index.js
@@ -1,3 +1,4 @@
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
import React from 'react';
import { Title, PageSection } from '@patternfly/react-core';
diff --git a/packages/module/src/LogViewer/LogViewer.tsx b/packages/module/src/LogViewer/LogViewer.tsx
index a401d9c..1c0628a 100644
--- a/packages/module/src/LogViewer/LogViewer.tsx
+++ b/packages/module/src/LogViewer/LogViewer.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect, memo } from 'react';
+import { useState, useEffect, memo, useMemo, useRef, forwardRef } from 'react';
import { LogViewerContext, LogViewerToolbarContext } from './LogViewerContext';
import { css } from '@patternfly/react-styles';
import { LogViewerRow } from './LogViewerRow';
@@ -112,9 +112,9 @@ const LogViewerBase: React.FunctionComponent = memo(
const [listKey, setListKey] = useState(1);
/* Parse data every time it changes */
- const parsedData = React.useMemo(() => parseConsoleOutput(data), [data]);
+ const parsedData = useMemo(() => parseConsoleOutput(data), [data]);
- const isChrome = React.useMemo(() => navigator.userAgent.indexOf('Chrome') !== -1, []);
+ const isChrome = useMemo(() => navigator.userAgent.indexOf('Chrome') !== -1, []);
const ansiUp = new AnsiUp();
// eslint-disable-next-line camelcase
@@ -122,9 +122,9 @@ const LogViewerBase: React.FunctionComponent = memo(
// eslint-disable-next-line camelcase
ansiUp.use_classes = useAnsiClasses;
- const ref = React.useRef();
+ const ref = useRef(null);
const logViewerRef = innerRef || ref;
- const containerRef = React.useRef();
+ const containerRef = useRef(null);
let resizeTimer = null as any;
useEffect(() => {
@@ -154,7 +154,7 @@ const LogViewerBase: React.FunctionComponent = memo(
setLoading(resizing);
}, [resizing]);
- const dataToRender = React.useMemo(
+ const dataToRender = useMemo(
() => ({
parsedData,
logViewerRef,
@@ -250,11 +250,11 @@ const LogViewerBase: React.FunctionComponent = memo(
dummyText.innerHTML = rowText;
logViewerList.appendChild(dummyText);
- const computedHeight = dummyText.clientHeight
+ const computedHeight = dummyText.clientHeight;
logViewerList.removeChild(dummyText);
- return computedHeight
- }
+ return computedHeight;
+ };
const guessRowHeight = (rowIndex: number) => {
if (!isTextWrapped) {
@@ -267,14 +267,14 @@ const LogViewerBase: React.FunctionComponent = memo(
// multiply by line height to get the total height
const heightGuess = lineHeight * (numRows || 1);
- // because of a bug in react-window (which seems to be limited to chrome) we need to
- // actually compute row height in long lines to prevent them from overflowing.
+ // because of a bug in react-window (which seems to be limited to chrome) we need to
+ // actually compute row height in long lines to prevent them from overflowing.
// related issue https://github.com/bvaughn/react-window/issues/593
if (rowText.length > fastRowHeightEstimationLimit && isChrome && isTextWrapped) {
return computeRowHeight(rowText, heightGuess);
}
- return heightGuess
+ return heightGuess;
};
const createList = (parsedData: string[]) => (
@@ -351,7 +351,7 @@ const LogViewerBase: React.FunctionComponent = memo(
areEqual
);
-export const LogViewer = React.forwardRef((props: LogViewerProps, ref: React.Ref) => (
+export const LogViewer = forwardRef((props: LogViewerProps, ref: React.Ref) => (
} {...props} />
));
diff --git a/packages/module/src/LogViewer/LogViewerRow.tsx b/packages/module/src/LogViewer/LogViewerRow.tsx
index 41d2f96..edcfe12 100644
--- a/packages/module/src/LogViewer/LogViewerRow.tsx
+++ b/packages/module/src/LogViewer/LogViewerRow.tsx
@@ -1,4 +1,4 @@
-import React, { memo, useContext } from 'react';
+import { memo, useContext } from 'react';
import { LOGGER_LINE_NUMBER_INDEX_DELTA } from './utils/constants';
import { css } from '@patternfly/react-styles';
import styles from './css/log-viewer';
@@ -27,7 +27,7 @@ export const LogViewerRow: React.FunctionComponent = memo(({
/** Helper function for applying the correct styling for styling rows containing searched keywords */
const handleHighlight = (matchCounter: number) => {
- const searchedWordResult = searchedWordIndexes.filter(searchedWord => searchedWord.rowIndex === index);
+ const searchedWordResult = searchedWordIndexes.filter((searchedWord) => searchedWord.rowIndex === index);
if (searchedWordResult.length !== 0) {
if (rowInFocus.rowIndex === index && rowInFocus.matchIndex === matchCounter) {
return styles.modifiers.current;
@@ -44,7 +44,7 @@ export const LogViewerRow: React.FunctionComponent = memo(({
const splitAnsiString = splitAnsi(rowText);
const regEx = new RegExp(`(${escapeString(context.searchedInput)})`, 'ig');
const composedString: string[] = [];
- splitAnsiString.forEach(str => {
+ splitAnsiString.forEach((str) => {
matchCounter = 0;
if (isAnsi(str)) {
composedString.push(str);
@@ -53,7 +53,9 @@ export const LogViewerRow: React.FunctionComponent = memo(({
splitString.forEach((substr) => {
if (substr.match(regEx)) {
matchCounter += 1;
- composedString.push(`${substr}`);
+ composedString.push(
+ `${substr}`
+ );
} else {
composedString.push(escapeTextForHtml(substr));
}
diff --git a/packages/module/src/LogViewer/LogViewerSearch.tsx b/packages/module/src/LogViewer/LogViewerSearch.tsx
index bcd916f..a4add23 100644
--- a/packages/module/src/LogViewer/LogViewerSearch.tsx
+++ b/packages/module/src/LogViewer/LogViewerSearch.tsx
@@ -1,4 +1,4 @@
-import React, { useContext, useEffect, useState } from 'react';
+import { useContext, useEffect, useState } from 'react';
import {
NUMBER_INDEX_DELTA,
DEFAULT_FOCUS,
@@ -108,15 +108,15 @@ export const LogViewerSearch: React.FunctionComponent = ({
props.onChange && props.onChange(event, input);
setSearchedInput(input);
}}
- onNextClick={event => {
+ onNextClick={(event) => {
props.onNextClick && props.onNextClick(event);
handleNextSearchItem();
}}
- onPreviousClick={event => {
+ onPreviousClick={(event) => {
props.onPreviousClick && props.onPreviousClick(event);
handlePrevSearchItem();
}}
- onClear={event => {
+ onClear={(event) => {
props.onClear && props.onClear(event);
handleClear();
}}
diff --git a/packages/module/src/LogViewer/__test__/Logviewer.test.tsx b/packages/module/src/LogViewer/__test__/Logviewer.test.tsx
index 6ed46aa..885cc6d 100644
--- a/packages/module/src/LogViewer/__test__/Logviewer.test.tsx
+++ b/packages/module/src/LogViewer/__test__/Logviewer.test.tsx
@@ -1,16 +1,15 @@
-import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import 'jest-canvas-mock';
import { LogViewer } from '../LogViewer';
-import { data } from './realTestData'
+import { data } from './realTestData';
test('Renders without children', () => {
render(
-
+
- )
+ );
- expect(screen.getByTestId('container').firstChild).toBeVisible();
+ expect(screen.getByTestId('container').firstChild).toBeVisible();
});
diff --git a/packages/module/tsconfig.json b/packages/module/tsconfig.json
index d353f05..a1b5b44 100644
--- a/packages/module/tsconfig.json
+++ b/packages/module/tsconfig.json
@@ -4,38 +4,28 @@
/* Basic Options */
"assumeChangesOnlyAffectDirectDependencies": true,
- "incremental": true, /* Enable incremental compilation */
+ "incremental": true /* Enable incremental compilation */,
"target": "es2015" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */,
"module": "es2015" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
- "jsx": "react" /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */,
- "lib": [
- "es2015",
- "dom"
- ],
+ "jsx": "react-jsx" /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */,
+ "lib": ["es2015", "dom"],
"declaration": true /* Generates corresponding '.d.ts' file. */,
- "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
- "sourceMap": true, /* Generates corresponding '.map' file. */
+ "declarationMap": true /* Generates a sourcemap for each corresponding '.d.ts' file. */,
+ "sourceMap": true /* Generates corresponding '.map' file. */,
"outDir": "./dist/esm" /* Redirect output structure to the directory. */,
"rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
"strict": true /* Enable all strict type-checking options. */,
"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
"skipLibCheck": true /* Skip type checking of declaration files. */,
- "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
+ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
"strictNullChecks": false,
"isolatedModules": true,
"importHelpers": true,
"composite": true,
- "plugins": [
- { "transform": "transformer-cjs-imports" }
- ],
+ "plugins": [{ "transform": "transformer-cjs-imports" }],
"tsBuildInfoFile": "dist/esm.tsbuildinfo"
},
"include": ["./src/*", "./src/**/*", "tsconfig.cjs.json"],
- "exclude": [
- "**/**.test.tsx",
- "**/**.test.ts",
- "**/examples/**",
- "**/__mocks__/**"
- ]
+ "exclude": ["**/**.test.tsx", "**/**.test.ts", "**/examples/**", "**/__mocks__/**"]
}