Skip to content

Commit

Permalink
Merge branch 'main' into RHCLOUD-31243
Browse files Browse the repository at this point in the history
  • Loading branch information
aferd authored Apr 2, 2024
2 parents 21bfcdb + eebfbe3 commit 720b7a8
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 4 deletions.
127 changes: 124 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,133 @@
# PatternFly Virtual Assistant

This repo contains react virtual assistant implementation.
This repo contains React Virtual assistant implementation.

---
## Contribution guide

## Building for production
### To add a new assistant sub-component:
1. create a folder in `src/` matching its name (for example `src/MyComponent`)
2. to the new folder add a new `.tsx` file named after the component (for example `src/MyComponent/MyComponent.tsx`)
3. to the same folder include an `index.ts` which will export the component as a default and then all necessary interfaces
4. if this file structure is not met, your component won't be exposed correctly

#### Example component:
```
import * as React from 'react';
import { Text } from '@patternfly/react-core';
import { createUseStyles } from 'react-jss';
// do not forget to export your component's interface
// always place the component's interface above the component itself in the code
export interface MyComponentProps {
text: String;
}
const useStyles = createUseStyles({
myText: {
fontFamily: 'monospace',
fontSize: 'var(--pf-v5-global--icon--FontSize--md)',
},
})
// do not use the named export of your component, just a default one
const MyComponent: React.FunctionComponent<MyComponentProps> = () => {
const classes = useStyles();
return (
<Text className={classes.myText}>
This is my new component
</Text>
);
};
export default MyComponent;
```

#### Index file example:
```
export { default } from './MyComponent';
export * from './MyComponent';
```

#### Component directory structure example:
```
src
|- MyComponent
|- index.ts
|- MyComponent.tsx
```

### Component's API rules:
- prop names comply with PatternFly components naming standards (`variant`, `onClick`, `position`, etc.)
- the API is maximally simplified and all props are provided with a description
- it is built on top of existing PatternFly types without prop omitting
- it is well documented using the PatternFly documentation (`/packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/MyComponent/MyComponent.md`) with examples of all possible use cases (`packages/module/patternfly-docs/content/extensions/virtual-assistant/examples/MyComponent/MyComponent[...]Example.tsx`)

#### Component API definition example:
```
// when possible, extend available PatternFly types
export interface MyComponentProps extends ButtonProps {
customLabel: Boolean
};
export const MyComponent: React.FunctionComponent<MyComponentProps> = ({ customLabel, ...props }) => ( ... );
```

#### Markdown file example:
```
---
section: extensions
subsection: Virtual assistant
id: MyComponent
propComponents: ['MyComponent']
---
import MyComponent from "@patternfly/virtual-assistant/dist/dynamic/MyComponent";
## Component usage
MyComponent has been created to demo contributing to this repository.
### MyComponent component example label
```js file="./MyComponentExample.tsx"```
```

#### Component usage file example: (`MyComponentExample.tsx`)
```
import React from 'react';
const MyComponentExample: React.FunctionComponent = () => (
<MyComponent customLabel="My label">
);
export default BatteryLowExample;
```

### Sub-components:
When adding a component for which it is advantageous to divide it into several sub-components make sure:
- component and all its sub-components are located in separate files and directories straight under the `src/` folder
- sub-components are exported and documented separately from their parent
- parent component should provide a way to pass props to all its sub-components

The aim is to enable the user of our "complex" component to use either complete or take advantage of its sub-components and manage their composition independently.

### Testing:
When adding/making changes to a component, always make sure your code is tested:
- use React Testing Library for testing
- add tests to a `[ComponentName].test.tsx` file to your component's directory
- make sure all the core logic is covered

### Styling:
- for styling always use JSS
- new classNames should be named in camelCase starting with the name of a given component and following with more details clarifying its purpose/component's subsection to which the class is applied (`actionMenu`, `actionMenuDropdown`, `actionMenuDropdownToggle`, etc.)
- do not use `pf-v5-u-XXX` classes, use CSS variables in a custom class instead (styles for the utility classes are not bundled with the standard patternfly.css - it would require the consumer to import also addons.css)

---

## Building for production
- run npm install
- run npm run build

Expand All @@ -18,7 +140,6 @@ This repo contains react virtual assistant implementation.
- run npm run lint to run the linter

## A11y testing

- run npm run build:docs followed by npm run serve:docs, then run npm run test:a11y in a new terminal window to run our accessibility tests. Once the accessibility tests have finished running you can run
- npm run serve:a11y to locally view the generated report

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ sourceLink: https://github.com/patternfly/virtual-assistant/blob/main/packages/m

import VirtualAssistant from '@patternfly/virtual-assistant/dist/dynamic/VirtualAssistant';
import VirtualAssistantAction from '@patternfly/virtual-assistant/dist/dynamic/VirtualAssistantAction';
import LoadingMessage from '@patternfly/virtual-assistant/dist/dynamic/LoadingMessage';
import { GrinIcon } from '@patternfly/react-icons';
import { AngleDownIcon } from '@patternfly/react-icons';

The **virtual assistant** component renders body of the virtual assistant window.
Expand Down Expand Up @@ -61,11 +63,21 @@ Custom actions can be added to the assistant body using the `actions` property.
```js file="./VirtualAssistantWithActions.tsx"

```

### System Message Entry

The `SystemMessageEntry` component provides a simple system message with an option for text links.


```js file="./VirtualAssistantSystemMessageEntry.tsx"

```
```

### Loading Messages

The `LoadingMessage` component shows a typing indicator for messages still being processed, introducing an intentional delay to simulate a smoother flow of conversation. Additionally, it allows for the use of a custom icon through the `icon` property.


```js file="./VirtualAssistantLoadingMessage.tsx"

```
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import VirtualAssistant from '@patternfly/virtual-assistant/dist/dynamic/VirtualAssistant';
import LoadingMessage from '@patternfly/virtual-assistant/dist/esm/LoadingMessage'
import GrinIcon from '@patternfly/react-icons/dist/js/icons/bacon-icon';

export const BasicExample: React.FunctionComponent = () => (
<VirtualAssistant >
<LoadingMessage />
<LoadingMessage icon={GrinIcon} />
</VirtualAssistant>
);
86 changes: 86 additions & 0 deletions packages/module/src/LoadingMessage/LoadingMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React from 'react';
import { Icon, Split, SplitItem } from '@patternfly/react-core';
import { createUseStyles } from 'react-jss';
import classnames from "clsx";

import RobotIcon from '@patternfly/react-icons/dist/js/icons/robot-icon';

const useStyles = createUseStyles({
chatbot: {
marginBottom: "var(--pf-v5-global--spacer--md)",
marginRight: "40px",
},
bubble: {
border: "1px solid var(--pf-v5-global--BackgroundColor--dark-400)",
borderRadius: "14px",
padding: "var(--pf-v5-global--spacer--sm) var(--pf-v5-global--spacer--md) var(--pf-v5-global--spacer--sm) var(--pf-v5-global--spacer--md)",
maxWidth: "100%",
wordWrap: "break-word",
},
"@keyframes mercuryTypingAnimation": {
"0%": {
transform: "translateY(0px)",
backgroundColor: "var(--pf-v5-global--palette--black-600)",
},
"28%": {
transform: "translateY(-7px)",
backgroundColor: "var(--pf-v5-global--palette--black-400)",
},
"44%": {
transform: "translateY(0px)",
backgroundColor: "var(--pf-v5-global--palette--black-200)",
}
},
dot: {},
typing: {
height: "17px",
"& $dot": {
animation: "$mercuryTypingAnimation 1.8s infinite ease-in-out",
borderRadius: "50%",
display: "inline-block",
height: "7px",
marginRight: "4px",
marginTop: "6px",
verticalAlign: "middle",
width: "7px",
"&:nth-child(1)": {
animationDelay: "200ms",
},
"&:nth-child(2)": {
animationDelay: "300ms",
},
"&:nth-child(3)": {
animationDelay: "400ms",
},
"&:last-child": {
marginRight: "0",
},
}
}
})

export interface LoadingMessageProps {
icon?: React.ComponentClass;
}

export const LoadingMessage: React.FunctionComponent<LoadingMessageProps> = ({ icon: IconComponent = RobotIcon }) => {
const classes = useStyles();
return (
<Split className={classes.chatbot}>
<SplitItem>
<Icon size="lg" className="pf-v5-u-mr-sm pf-v5-u-pt-md">
<IconComponent />
</Icon>
</SplitItem>
<SplitItem className={classnames(classes.bubble," pf-u-background-color-200")} >
<div className={classnames(classes.typing,"pf-v5-u-display-flex pf-u-align-items-center")}>
<div className={classes.dot}></div>
<div className={classes.dot}></div>
<div className={classes.dot}></div>
</div>
</SplitItem>
</Split>
);
};

export default LoadingMessage;
3 changes: 3 additions & 0 deletions packages/module/src/LoadingMessage/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { default } from './LoadingMessage';

export * from './LoadingMessage';
3 changes: 3 additions & 0 deletions packages/module/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
// this file is autogenerated by generate-index.js, modifying it manually will have no effect

export { default as LoadingMessage } from './LoadingMessage';
export * from './LoadingMessage';

export { default as VirtualAssistant } from './VirtualAssistant';
export * from './VirtualAssistant';

Expand Down

0 comments on commit 720b7a8

Please sign in to comment.