From 828db6a72eb8c974b9074e4566d5ab1c294fe8c3 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Mon, 19 Jun 2023 18:07:57 +0200 Subject: [PATCH 01/29] Add simple chat --- package.json | 3 +- packages/accessible-chat/.eslintrc.json | 24 +++++++ packages/accessible-chat/.storybook/main.ts | 16 +++++ .../accessible-chat/.storybook/preview.tsx | 17 +++++ .../accessible-chat/.storybook/tsconfig.json | 27 ++++++++ packages/accessible-chat/.swcrc | 30 +++++++++ packages/accessible-chat/README.md | 11 ++++ packages/accessible-chat/jest.config.ts | 29 +++++++++ packages/accessible-chat/package.json | 12 ++++ packages/accessible-chat/project.json | 65 +++++++++++++++++++ .../AccessibleChat/AccessibleChat.styles.ts | 22 +++++++ .../AccessibleChat/AccessibleChat.test.tsx | 9 +++ .../AccessibleChat/AccessibleChat.tsx | 38 +++++++++++ .../src/components/AccessibleChat/index.ts | 1 + packages/accessible-chat/src/index.ts | 2 + .../AccessibleChat/Default.stories.tsx | 4 ++ .../stories/AccessibleChat/index.stories.tsx | 10 +++ packages/accessible-chat/tsconfig.json | 19 ++++++ packages/accessible-chat/tsconfig.lib.json | 19 ++++++ packages/accessible-chat/tsconfig.spec.json | 14 ++++ tsconfig.base.json | 3 + 21 files changed, 374 insertions(+), 1 deletion(-) create mode 100644 packages/accessible-chat/.eslintrc.json create mode 100644 packages/accessible-chat/.storybook/main.ts create mode 100644 packages/accessible-chat/.storybook/preview.tsx create mode 100644 packages/accessible-chat/.storybook/tsconfig.json create mode 100644 packages/accessible-chat/.swcrc create mode 100644 packages/accessible-chat/README.md create mode 100644 packages/accessible-chat/jest.config.ts create mode 100644 packages/accessible-chat/package.json create mode 100644 packages/accessible-chat/project.json create mode 100644 packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.styles.ts create mode 100644 packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.test.tsx create mode 100644 packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx create mode 100644 packages/accessible-chat/src/components/AccessibleChat/index.ts create mode 100644 packages/accessible-chat/src/index.ts create mode 100644 packages/accessible-chat/stories/AccessibleChat/Default.stories.tsx create mode 100644 packages/accessible-chat/stories/AccessibleChat/index.stories.tsx create mode 100644 packages/accessible-chat/tsconfig.json create mode 100644 packages/accessible-chat/tsconfig.lib.json create mode 100644 packages/accessible-chat/tsconfig.spec.json diff --git a/package.json b/package.json index 9a24dcc49..c08f8b545 100644 --- a/package.json +++ b/package.json @@ -62,5 +62,6 @@ "ts-node": "10.9.1", "tslib": "^2.3.0", "typescript": "~5.0.2" - } + }, + "dependencies": {} } diff --git a/packages/accessible-chat/.eslintrc.json b/packages/accessible-chat/.eslintrc.json new file mode 100644 index 000000000..5f831ca3a --- /dev/null +++ b/packages/accessible-chat/.eslintrc.json @@ -0,0 +1,24 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["stories/**/*.tsx", "stories/**/*.ts"], + "rules": { + "@nx/enforce-module-boundaries": "off" + } + } + ] +} diff --git a/packages/accessible-chat/.storybook/main.ts b/packages/accessible-chat/.storybook/main.ts new file mode 100644 index 000000000..be3137a2e --- /dev/null +++ b/packages/accessible-chat/.storybook/main.ts @@ -0,0 +1,16 @@ +import type { StorybookConfig } from '@storybook/react-webpack5'; + +const config: StorybookConfig = { + stories: ['../stories/**/index.stories.@(js|jsx|ts|tsx|mdx)'], + addons: ['@storybook/addon-essentials', '@nx/react/plugins/storybook'], + framework: { + name: '@storybook/react-webpack5', + options: {}, + }, +}; + +export default config; + +// To customize your webpack configuration you can use the webpackFinal field. +// Check https://storybook.js.org/docs/react/builders/webpack#extending-storybooks-webpack-config +// and https://nx.dev/packages/storybook/documents/custom-builder-configs diff --git a/packages/accessible-chat/.storybook/preview.tsx b/packages/accessible-chat/.storybook/preview.tsx new file mode 100644 index 000000000..5f63e6515 --- /dev/null +++ b/packages/accessible-chat/.storybook/preview.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; + +import { Preview } from '@storybook/react'; + +import { FluentProvider, webLightTheme } from '@fluentui/react-components'; + +const preview: Preview = { + decorators: [ + (Story) => ( + + + + ), + ], +}; + +export default preview; diff --git a/packages/accessible-chat/.storybook/tsconfig.json b/packages/accessible-chat/.storybook/tsconfig.json new file mode 100644 index 000000000..6fa15c2f4 --- /dev/null +++ b/packages/accessible-chat/.storybook/tsconfig.json @@ -0,0 +1,27 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "emitDecoratorMetadata": true, + "outDir": "" + }, + "files": [ + "../../../node_modules/@nx/react/typings/styled-jsx.d.ts", + "../../../node_modules/@nx/react/typings/cssmodule.d.ts", + "../../../node_modules/@nx/react/typings/image.d.ts" + ], + "exclude": [ + "../**/*.spec.ts", + "../**/*.spec.js", + "../**/*.spec.tsx", + "../**/*.spec.jsx" + ], + "include": [ + "../stories/**/*.stories.ts", + "../stories/**/*.stories.js", + "../stories/**/*.stories.jsx", + "../stories/**/*.stories.tsx", + "../stories/**/*.stories.mdx", + "*.ts", + "*.js" + ] +} diff --git a/packages/accessible-chat/.swcrc b/packages/accessible-chat/.swcrc new file mode 100644 index 000000000..8c4f5c696 --- /dev/null +++ b/packages/accessible-chat/.swcrc @@ -0,0 +1,30 @@ +{ + "jsc": { + "target": "es2020", + "parser": { + "syntax": "typescript", + "tsx": true, + "decorators": false, + "dynamicImport": false + }, + "transform": { + "react": { + "runtime": "classic", + "useSpread": true + } + }, + "keepClassNames": true, + "externalHelpers": true, + "loose": true + }, + "sourceMaps": true, + "exclude": [ + "jest.config.ts", + ".*\\.spec.tsx?$", + ".*\\.test.tsx?$", + "./src/jest-setup.ts$", + "./**/jest-setup.ts$", + ".*.js$" + ], + "$schema": "https://json.schemastore.org/swcrc" +} diff --git a/packages/accessible-chat/README.md b/packages/accessible-chat/README.md new file mode 100644 index 000000000..f25781f88 --- /dev/null +++ b/packages/accessible-chat/README.md @@ -0,0 +1,11 @@ +# accessible-chat + +This library was generated with [Nx](https://nx.dev). + +## Building + +Run `nx build accessible-chat` to build the library. + +## Running unit tests + +Run `nx test accessible-chat` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/packages/accessible-chat/jest.config.ts b/packages/accessible-chat/jest.config.ts new file mode 100644 index 000000000..80b8addcb --- /dev/null +++ b/packages/accessible-chat/jest.config.ts @@ -0,0 +1,29 @@ +/* eslint-disable */ +import { readFileSync } from 'fs'; + +// Reading the SWC compilation config and remove the "exclude" +// for the test files to be compiled by SWC +const { exclude: _, ...swcJestConfig } = JSON.parse( + readFileSync(`${__dirname}/.swcrc`, 'utf-8') +); + +// disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves. +// If we do not disable this, SWC Core will read .swcrc and won't transform our test files due to "exclude" +if (swcJestConfig.swcrc === undefined) { + swcJestConfig.swcrc = false; +} + +// Uncomment if using global setup/teardown files being transformed via swc +// https://nx.dev/packages/jest/documents/overview#global-setup/teardown-with-nx-libraries +// jest needs EsModule Interop to find the default exported setup/teardown functions +// swcJestConfig.module.noInterop = false; + +export default { + displayName: 'button', + preset: '../../jest.preset.js', + transform: { + '^.+\\.[tj]sx?$': ['@swc/jest', swcJestConfig], + }, + moduleFileExtensions: ['js', 'ts', 'tsx', 'html'], + coverageDirectory: '../../coverage/packages/button', +}; diff --git a/packages/accessible-chat/package.json b/packages/accessible-chat/package.json new file mode 100644 index 000000000..b365f11b5 --- /dev/null +++ b/packages/accessible-chat/package.json @@ -0,0 +1,12 @@ +{ + "name": "@fluentui-contrib/accessible-chat", + "version": "0.0.1", + "private": true, + "peerDependencies": { + "@fluentui/react-components": ">=9.20.0 <10.0.0", + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } +} diff --git a/packages/accessible-chat/project.json b/packages/accessible-chat/project.json new file mode 100644 index 000000000..d5092269b --- /dev/null +++ b/packages/accessible-chat/project.json @@ -0,0 +1,65 @@ +{ + "name": "accessible-chat", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/accessible-chat/src", + "projectType": "library", + "targets": { + "build": { + "executor": "@fluentui-contrib/nx-plugin:build" + }, + "publish": { + "command": "node tools/scripts/publish.mjs accessible-chat {args.ver} {args.tag}", + "dependsOn": ["build"] + }, + "lint": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["packages/accessible-chat/**/*.ts"] + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "packages/accessible-chat/jest.config.ts", + "passWithNoTests": true + }, + "configurations": { + "ci": { + "ci": true, + "codeCoverage": true + } + } + }, + "type-check": { + "executor": "@fluentui-contrib/nx-plugin:type-check" + }, + "storybook": { + "executor": "@nx/storybook:storybook", + "options": { + "port": 4400, + "configDir": "packages/accessible-chat/.storybook" + }, + "configurations": { + "ci": { + "quiet": true + } + } + }, + "build-storybook": { + "executor": "@nx/storybook:build", + "outputs": ["{options.outputDir}"], + "options": { + "outputDir": "dist/storybook/accessible-chat", + "configDir": "packages/accessible-chat/.storybook" + }, + "configurations": { + "ci": { + "quiet": true + } + } + } + }, + "tags": [] +} diff --git a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.styles.ts b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.styles.ts new file mode 100644 index 000000000..b54388da8 --- /dev/null +++ b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.styles.ts @@ -0,0 +1,22 @@ +import { makeStyles, shorthands, tokens } from '@fluentui/react-components'; + +export const useStyles = makeStyles({ + root: { + ...shorthands.padding(tokens.spacingHorizontalM), + ...shorthands.border( + tokens.strokeWidthThin, + 'solid', + tokens.colorNeutralStroke1 + ), + color: tokens.colorNeutralForeground1, + backgroundColor: tokens.colorNeutralBackground1, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + maxWidth: '200px', + ':hover': { + backgroundColor: tokens.colorNeutralBackground1Hover, + color: tokens.colorNeutralForeground1Hover, + }, + }, +}); diff --git a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.test.tsx b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.test.tsx new file mode 100644 index 000000000..5a314354f --- /dev/null +++ b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.test.tsx @@ -0,0 +1,9 @@ +import * as React from 'react'; +import { render } from '@testing-library/react'; +import { AccessibleChat } from './AccessibleChat'; + +describe('AccessibleChat', () => { + it('should render', () => { + render(); + }); +}); diff --git a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx new file mode 100644 index 000000000..42e0e6d39 --- /dev/null +++ b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; + +import { + mergeClasses, + Avatar, + PresenceBadgeStatus, +} from '@fluentui/react-components'; +import { Chat, ChatMessage, ChatMyMessage } from '@fluentui-contrib/react-chat'; + +import { useStyles } from './AccessibleChat.styles'; + +interface User { + name: string; + status: PresenceBadgeStatus; +} +export const AccessibleChat: React.FC = () => { + const styles = useStyles(); + + const user1: User = {name: 'Ashley McCarthy', status: 'available'}; + + return ( +
+ +

Accessible chat

+ + + }>Hello I am Ashley + Nice to meet you! + }> +
+ This is my homepage. Some text goes here to demonstrate reading of longer runsof texts. Now follows another link which is also a dummy link. +
+
+
+ +
+ ); +}; diff --git a/packages/accessible-chat/src/components/AccessibleChat/index.ts b/packages/accessible-chat/src/components/AccessibleChat/index.ts new file mode 100644 index 000000000..06d78381d --- /dev/null +++ b/packages/accessible-chat/src/components/AccessibleChat/index.ts @@ -0,0 +1 @@ +export * from './AccessibleChat'; diff --git a/packages/accessible-chat/src/index.ts b/packages/accessible-chat/src/index.ts new file mode 100644 index 000000000..00bdbd2da --- /dev/null +++ b/packages/accessible-chat/src/index.ts @@ -0,0 +1,2 @@ +export * from './components/AccessibleChat'; +export {}; diff --git a/packages/accessible-chat/stories/AccessibleChat/Default.stories.tsx b/packages/accessible-chat/stories/AccessibleChat/Default.stories.tsx new file mode 100644 index 000000000..eaebb836f --- /dev/null +++ b/packages/accessible-chat/stories/AccessibleChat/Default.stories.tsx @@ -0,0 +1,4 @@ +import * as React from 'react'; +import { AccessibleChat } from '@fluentui-contrib/accessible-chat'; + +export const Default = () => ; diff --git a/packages/accessible-chat/stories/AccessibleChat/index.stories.tsx b/packages/accessible-chat/stories/AccessibleChat/index.stories.tsx new file mode 100644 index 000000000..5153a27f2 --- /dev/null +++ b/packages/accessible-chat/stories/AccessibleChat/index.stories.tsx @@ -0,0 +1,10 @@ +import * as React from 'react'; +import { Meta } from '@storybook/react'; +import { AccessibleChat } from '@fluentui-contrib/accessible-chat'; +export { Default } from './Default.stories'; + +const meta: Meta = { + component: AccessibleChat, +}; + +export default meta; diff --git a/packages/accessible-chat/tsconfig.json b/packages/accessible-chat/tsconfig.json new file mode 100644 index 000000000..15d0c1cab --- /dev/null +++ b/packages/accessible-chat/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "compilerOptions": { + "jsx": "react" + }, + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + }, + { + "path": "./.storybook/tsconfig.json" + } + ] +} diff --git a/packages/accessible-chat/tsconfig.lib.json b/packages/accessible-chat/tsconfig.lib.json new file mode 100644 index 000000000..b331bf1ff --- /dev/null +++ b/packages/accessible-chat/tsconfig.lib.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.test.tsx", + "files/**", + "**/*.stories.ts", + "**/*.stories.js", + "**/*.stories.jsx", + "**/*.stories.tsx" + ] +} diff --git a/packages/accessible-chat/tsconfig.spec.json b/packages/accessible-chat/tsconfig.spec.json new file mode 100644 index 000000000..361fd5a7e --- /dev/null +++ b/packages/accessible-chat/tsconfig.spec.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.test.tsx", + "src/**/*.d.ts" + ] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 7914b1638..c8127e1bc 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -15,6 +15,9 @@ "skipDefaultLibCheck": true, "baseUrl": ".", "paths": { + "@fluentui-contrib/accessible-chat": [ + "packages/accessible-chat/src/index.ts" + ], "@fluentui-contrib/nx-plugin": ["packages/nx-plugin/src/index.ts"], "@fluentui-contrib/react-chat": ["packages/react-chat/src/index.ts"] } From df7138117e0de240d0a070f11b54e18f63be35c3 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Mon, 19 Jun 2023 19:10:25 +0200 Subject: [PATCH 02/29] Add Control + Enter behavior on messageContorl --- .../AccessibleChat/AccessibleChat.tsx | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx index 42e0e6d39..aa4360a7e 100644 --- a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx +++ b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx @@ -5,7 +5,11 @@ import { Avatar, PresenceBadgeStatus, } from '@fluentui/react-components'; -import { Chat, ChatMessage, ChatMyMessage } from '@fluentui-contrib/react-chat'; +import { + Chat, + ChatMessage, + ChatMyMessage, + } from '@fluentui-contrib/react-chat'; import { useStyles } from './AccessibleChat.styles'; @@ -18,6 +22,14 @@ export const AccessibleChat: React.FC = () => { const user1: User = {name: 'Ashley McCarthy', status: 'available'}; + const handleMessageKeyDown = (id) => { +return (event) => { + if (event.ctrlKey && event.key === 'Enter') { +document.getElementById(id).focus(); +} +}; + }; + return (
@@ -26,8 +38,11 @@ export const AccessibleChat: React.FC = () => { }>Hello I am Ashley Nice to meet you! - }> -
+ } + onKeyDown={handleMessageKeyDown('message3-content')} + > +
This is my homepage. Some text goes here to demonstrate reading of longer runsof texts. Now follows another link which is also a dummy link.
From 88a339c450365de237ec09da417bdb526c4bd0c8 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Mon, 19 Jun 2023 22:08:53 +0200 Subject: [PATCH 03/29] Refactor chat messages --- .../AccessibleChat/AccessibleChat.tsx | 76 +++++++++++++------ 1 file changed, 52 insertions(+), 24 deletions(-) diff --git a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx index aa4360a7e..bb5159a61 100644 --- a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx +++ b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx @@ -9,45 +9,73 @@ import { Chat, ChatMessage, ChatMyMessage, - } from '@fluentui-contrib/react-chat'; +} from '@fluentui-contrib/react-chat'; import { useStyles } from './AccessibleChat.styles'; +const ChatMessageContent = ({ id, children }) => ( +
{children}
+); + interface User { name: string; status: PresenceBadgeStatus; } -export const AccessibleChat: React.FC = () => { - const styles = useStyles(); - - const user1: User = {name: 'Ashley McCarthy', status: 'available'}; - const handleMessageKeyDown = (id) => { -return (event) => { - if (event.ctrlKey && event.key === 'Enter') { -document.getElementById(id).focus(); +interface ExtendedChatMessageProps { +user?; +contentId; +children; } -}; +const ExtendedChatMessage: React.FC = ({ user, contentId, children, ...props }) => { + const handleMessageKeyDown = (event) => { + if (event.ctrlKey && event.key === 'Enter') { + document.getElementById(contentId).focus(); + } }; return ( -
- -

Accessible chat

- - - }>Hello I am Ashley - Nice to meet you! + <> + {!user ? ( + + {children} + + ) : ( } - onKeyDown={handleMessageKeyDown('message3-content')} + avatar={} + onKeyDown={handleMessageKeyDown} > -
- This is my homepage. Some text goes here to demonstrate reading of longer runsof texts. Now follows another link which is also a dummy link. -
+ {children}
-
+ )} + + ); +}; + +export const AccessibleChat: React.FC = () => { + const styles = useStyles(); + + const user1: User = { name: 'Ashley McCarthy', status: 'available' }; + + return ( +
+

Accessible chat

+ + + + Hello I am Ashley + Nice to meet you! + + This is my homepage. Some text goes here to demonstrate reading of longer runsof texts. Now follows another link which is also a dummy link. + + -
+
); }; From 76f14bc89d8feef3a4ea83e8f7b64a86758e53b7 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Tue, 20 Jun 2023 10:25:37 +0200 Subject: [PATCH 04/29] Add ...rest props --- .../src/components/AccessibleChat/AccessibleChat.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx index bb5159a61..c502596a3 100644 --- a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx +++ b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx @@ -13,8 +13,9 @@ import { import { useStyles } from './AccessibleChat.styles'; -const ChatMessageContent = ({ id, children }) => ( +const ChatMessageContent = ({ id, children, ...rest }) => (
( ); interface User { - name: string; - status: PresenceBadgeStatus; + name; + status; } interface ExtendedChatMessageProps { @@ -31,7 +32,7 @@ user?; contentId; children; } -const ExtendedChatMessage: React.FC = ({ user, contentId, children, ...props }) => { +const ExtendedChatMessage: React.FC = ({ user, contentId, children, ...rest }) => { const handleMessageKeyDown = (event) => { if (event.ctrlKey && event.key === 'Enter') { document.getElementById(contentId).focus(); @@ -42,12 +43,14 @@ const ExtendedChatMessage: React.FC = ({ user, content <> {!user ? ( {children} ) : ( } onKeyDown={handleMessageKeyDown} > From 5d7077c9869b54d9e39c034855fea178adaf6d9d Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Tue, 20 Jun 2023 10:42:09 +0200 Subject: [PATCH 05/29] Remove unnecessary role --- .../src/components/AccessibleChat/AccessibleChat.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx index c502596a3..4bd4273d8 100644 --- a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx +++ b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx @@ -16,7 +16,6 @@ import { useStyles } from './AccessibleChat.styles'; const ChatMessageContent = ({ id, children, ...rest }) => (
{children}
From 319ca6942f3974d812f0ca22861384648715c84f Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Tue, 20 Jun 2023 10:43:31 +0200 Subject: [PATCH 06/29] Reformat the code --- .../AccessibleChat/AccessibleChat.tsx | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx index 4bd4273d8..a98681fab 100644 --- a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx +++ b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx @@ -15,9 +15,9 @@ import { useStyles } from './AccessibleChat.styles'; const ChatMessageContent = ({ id, children, ...rest }) => (
{children}
); @@ -27,9 +27,9 @@ interface User { } interface ExtendedChatMessageProps { -user?; -contentId; -children; + user?; + contentId; + children; } const ExtendedChatMessage: React.FC = ({ user, contentId, children, ...rest }) => { const handleMessageKeyDown = (event) => { @@ -40,23 +40,23 @@ const ExtendedChatMessage: React.FC = ({ user, content return ( <> - {!user ? ( - - {children} + {!user ? ( + + {children} - ) : ( - } - onKeyDown={handleMessageKeyDown} - > - {children} - + ) : ( + } + onKeyDown={handleMessageKeyDown} + > + {children} + )} - + ); }; From 14ab9e704811c0eb341f6b27fa52035fd649ed50 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Tue, 20 Jun 2023 14:36:58 +0200 Subject: [PATCH 07/29] Move accessible chat to react-chat --- packages/accessible-chat/.eslintrc.json | 24 ------- packages/accessible-chat/.storybook/main.ts | 16 ----- .../accessible-chat/.storybook/preview.tsx | 17 ----- .../accessible-chat/.storybook/tsconfig.json | 27 -------- packages/accessible-chat/.swcrc | 30 --------- packages/accessible-chat/README.md | 11 ---- packages/accessible-chat/jest.config.ts | 29 --------- packages/accessible-chat/package.json | 12 ---- packages/accessible-chat/project.json | 65 ------------------- .../AccessibleChat/AccessibleChat.styles.ts | 22 ------- .../AccessibleChat/AccessibleChat.test.tsx | 9 --- .../src/components/AccessibleChat/index.ts | 1 - packages/accessible-chat/src/index.ts | 2 - .../AccessibleChat/Default.stories.tsx | 4 -- .../stories/AccessibleChat/index.stories.tsx | 10 --- packages/accessible-chat/tsconfig.json | 19 ------ packages/accessible-chat/tsconfig.lib.json | 19 ------ packages/accessible-chat/tsconfig.spec.json | 14 ---- .../stories/Chat/AccessibleChat.stories.tsx} | 6 +- .../react-chat/stories/Chat/index.stories.tsx | 1 + 20 files changed, 2 insertions(+), 336 deletions(-) delete mode 100644 packages/accessible-chat/.eslintrc.json delete mode 100644 packages/accessible-chat/.storybook/main.ts delete mode 100644 packages/accessible-chat/.storybook/preview.tsx delete mode 100644 packages/accessible-chat/.storybook/tsconfig.json delete mode 100644 packages/accessible-chat/.swcrc delete mode 100644 packages/accessible-chat/README.md delete mode 100644 packages/accessible-chat/jest.config.ts delete mode 100644 packages/accessible-chat/package.json delete mode 100644 packages/accessible-chat/project.json delete mode 100644 packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.styles.ts delete mode 100644 packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.test.tsx delete mode 100644 packages/accessible-chat/src/components/AccessibleChat/index.ts delete mode 100644 packages/accessible-chat/src/index.ts delete mode 100644 packages/accessible-chat/stories/AccessibleChat/Default.stories.tsx delete mode 100644 packages/accessible-chat/stories/AccessibleChat/index.stories.tsx delete mode 100644 packages/accessible-chat/tsconfig.json delete mode 100644 packages/accessible-chat/tsconfig.lib.json delete mode 100644 packages/accessible-chat/tsconfig.spec.json rename packages/{accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx => react-chat/stories/Chat/AccessibleChat.stories.tsx} (93%) diff --git a/packages/accessible-chat/.eslintrc.json b/packages/accessible-chat/.eslintrc.json deleted file mode 100644 index 5f831ca3a..000000000 --- a/packages/accessible-chat/.eslintrc.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "extends": ["../../.eslintrc.json"], - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], - "rules": {} - }, - { - "files": ["*.ts", "*.tsx"], - "rules": {} - }, - { - "files": ["*.js", "*.jsx"], - "rules": {} - }, - { - "files": ["stories/**/*.tsx", "stories/**/*.ts"], - "rules": { - "@nx/enforce-module-boundaries": "off" - } - } - ] -} diff --git a/packages/accessible-chat/.storybook/main.ts b/packages/accessible-chat/.storybook/main.ts deleted file mode 100644 index be3137a2e..000000000 --- a/packages/accessible-chat/.storybook/main.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { StorybookConfig } from '@storybook/react-webpack5'; - -const config: StorybookConfig = { - stories: ['../stories/**/index.stories.@(js|jsx|ts|tsx|mdx)'], - addons: ['@storybook/addon-essentials', '@nx/react/plugins/storybook'], - framework: { - name: '@storybook/react-webpack5', - options: {}, - }, -}; - -export default config; - -// To customize your webpack configuration you can use the webpackFinal field. -// Check https://storybook.js.org/docs/react/builders/webpack#extending-storybooks-webpack-config -// and https://nx.dev/packages/storybook/documents/custom-builder-configs diff --git a/packages/accessible-chat/.storybook/preview.tsx b/packages/accessible-chat/.storybook/preview.tsx deleted file mode 100644 index 5f63e6515..000000000 --- a/packages/accessible-chat/.storybook/preview.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import * as React from 'react'; - -import { Preview } from '@storybook/react'; - -import { FluentProvider, webLightTheme } from '@fluentui/react-components'; - -const preview: Preview = { - decorators: [ - (Story) => ( - - - - ), - ], -}; - -export default preview; diff --git a/packages/accessible-chat/.storybook/tsconfig.json b/packages/accessible-chat/.storybook/tsconfig.json deleted file mode 100644 index 6fa15c2f4..000000000 --- a/packages/accessible-chat/.storybook/tsconfig.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "emitDecoratorMetadata": true, - "outDir": "" - }, - "files": [ - "../../../node_modules/@nx/react/typings/styled-jsx.d.ts", - "../../../node_modules/@nx/react/typings/cssmodule.d.ts", - "../../../node_modules/@nx/react/typings/image.d.ts" - ], - "exclude": [ - "../**/*.spec.ts", - "../**/*.spec.js", - "../**/*.spec.tsx", - "../**/*.spec.jsx" - ], - "include": [ - "../stories/**/*.stories.ts", - "../stories/**/*.stories.js", - "../stories/**/*.stories.jsx", - "../stories/**/*.stories.tsx", - "../stories/**/*.stories.mdx", - "*.ts", - "*.js" - ] -} diff --git a/packages/accessible-chat/.swcrc b/packages/accessible-chat/.swcrc deleted file mode 100644 index 8c4f5c696..000000000 --- a/packages/accessible-chat/.swcrc +++ /dev/null @@ -1,30 +0,0 @@ -{ - "jsc": { - "target": "es2020", - "parser": { - "syntax": "typescript", - "tsx": true, - "decorators": false, - "dynamicImport": false - }, - "transform": { - "react": { - "runtime": "classic", - "useSpread": true - } - }, - "keepClassNames": true, - "externalHelpers": true, - "loose": true - }, - "sourceMaps": true, - "exclude": [ - "jest.config.ts", - ".*\\.spec.tsx?$", - ".*\\.test.tsx?$", - "./src/jest-setup.ts$", - "./**/jest-setup.ts$", - ".*.js$" - ], - "$schema": "https://json.schemastore.org/swcrc" -} diff --git a/packages/accessible-chat/README.md b/packages/accessible-chat/README.md deleted file mode 100644 index f25781f88..000000000 --- a/packages/accessible-chat/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# accessible-chat - -This library was generated with [Nx](https://nx.dev). - -## Building - -Run `nx build accessible-chat` to build the library. - -## Running unit tests - -Run `nx test accessible-chat` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/packages/accessible-chat/jest.config.ts b/packages/accessible-chat/jest.config.ts deleted file mode 100644 index 80b8addcb..000000000 --- a/packages/accessible-chat/jest.config.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* eslint-disable */ -import { readFileSync } from 'fs'; - -// Reading the SWC compilation config and remove the "exclude" -// for the test files to be compiled by SWC -const { exclude: _, ...swcJestConfig } = JSON.parse( - readFileSync(`${__dirname}/.swcrc`, 'utf-8') -); - -// disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves. -// If we do not disable this, SWC Core will read .swcrc and won't transform our test files due to "exclude" -if (swcJestConfig.swcrc === undefined) { - swcJestConfig.swcrc = false; -} - -// Uncomment if using global setup/teardown files being transformed via swc -// https://nx.dev/packages/jest/documents/overview#global-setup/teardown-with-nx-libraries -// jest needs EsModule Interop to find the default exported setup/teardown functions -// swcJestConfig.module.noInterop = false; - -export default { - displayName: 'button', - preset: '../../jest.preset.js', - transform: { - '^.+\\.[tj]sx?$': ['@swc/jest', swcJestConfig], - }, - moduleFileExtensions: ['js', 'ts', 'tsx', 'html'], - coverageDirectory: '../../coverage/packages/button', -}; diff --git a/packages/accessible-chat/package.json b/packages/accessible-chat/package.json deleted file mode 100644 index b365f11b5..000000000 --- a/packages/accessible-chat/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "@fluentui-contrib/accessible-chat", - "version": "0.0.1", - "private": true, - "peerDependencies": { - "@fluentui/react-components": ">=9.20.0 <10.0.0", - "@types/react": ">=16.8.0 <19.0.0", - "@types/react-dom": ">=16.8.0 <19.0.0", - "react": ">=16.8.0 <19.0.0", - "react-dom": ">=16.8.0 <19.0.0" - } -} diff --git a/packages/accessible-chat/project.json b/packages/accessible-chat/project.json deleted file mode 100644 index d5092269b..000000000 --- a/packages/accessible-chat/project.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "name": "accessible-chat", - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "packages/accessible-chat/src", - "projectType": "library", - "targets": { - "build": { - "executor": "@fluentui-contrib/nx-plugin:build" - }, - "publish": { - "command": "node tools/scripts/publish.mjs accessible-chat {args.ver} {args.tag}", - "dependsOn": ["build"] - }, - "lint": { - "executor": "@nx/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["packages/accessible-chat/**/*.ts"] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "packages/accessible-chat/jest.config.ts", - "passWithNoTests": true - }, - "configurations": { - "ci": { - "ci": true, - "codeCoverage": true - } - } - }, - "type-check": { - "executor": "@fluentui-contrib/nx-plugin:type-check" - }, - "storybook": { - "executor": "@nx/storybook:storybook", - "options": { - "port": 4400, - "configDir": "packages/accessible-chat/.storybook" - }, - "configurations": { - "ci": { - "quiet": true - } - } - }, - "build-storybook": { - "executor": "@nx/storybook:build", - "outputs": ["{options.outputDir}"], - "options": { - "outputDir": "dist/storybook/accessible-chat", - "configDir": "packages/accessible-chat/.storybook" - }, - "configurations": { - "ci": { - "quiet": true - } - } - } - }, - "tags": [] -} diff --git a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.styles.ts b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.styles.ts deleted file mode 100644 index b54388da8..000000000 --- a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.styles.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { makeStyles, shorthands, tokens } from '@fluentui/react-components'; - -export const useStyles = makeStyles({ - root: { - ...shorthands.padding(tokens.spacingHorizontalM), - ...shorthands.border( - tokens.strokeWidthThin, - 'solid', - tokens.colorNeutralStroke1 - ), - color: tokens.colorNeutralForeground1, - backgroundColor: tokens.colorNeutralBackground1, - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - maxWidth: '200px', - ':hover': { - backgroundColor: tokens.colorNeutralBackground1Hover, - color: tokens.colorNeutralForeground1Hover, - }, - }, -}); diff --git a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.test.tsx b/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.test.tsx deleted file mode 100644 index 5a314354f..000000000 --- a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.test.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import * as React from 'react'; -import { render } from '@testing-library/react'; -import { AccessibleChat } from './AccessibleChat'; - -describe('AccessibleChat', () => { - it('should render', () => { - render(); - }); -}); diff --git a/packages/accessible-chat/src/components/AccessibleChat/index.ts b/packages/accessible-chat/src/components/AccessibleChat/index.ts deleted file mode 100644 index 06d78381d..000000000 --- a/packages/accessible-chat/src/components/AccessibleChat/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './AccessibleChat'; diff --git a/packages/accessible-chat/src/index.ts b/packages/accessible-chat/src/index.ts deleted file mode 100644 index 00bdbd2da..000000000 --- a/packages/accessible-chat/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './components/AccessibleChat'; -export {}; diff --git a/packages/accessible-chat/stories/AccessibleChat/Default.stories.tsx b/packages/accessible-chat/stories/AccessibleChat/Default.stories.tsx deleted file mode 100644 index eaebb836f..000000000 --- a/packages/accessible-chat/stories/AccessibleChat/Default.stories.tsx +++ /dev/null @@ -1,4 +0,0 @@ -import * as React from 'react'; -import { AccessibleChat } from '@fluentui-contrib/accessible-chat'; - -export const Default = () => ; diff --git a/packages/accessible-chat/stories/AccessibleChat/index.stories.tsx b/packages/accessible-chat/stories/AccessibleChat/index.stories.tsx deleted file mode 100644 index 5153a27f2..000000000 --- a/packages/accessible-chat/stories/AccessibleChat/index.stories.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import * as React from 'react'; -import { Meta } from '@storybook/react'; -import { AccessibleChat } from '@fluentui-contrib/accessible-chat'; -export { Default } from './Default.stories'; - -const meta: Meta = { - component: AccessibleChat, -}; - -export default meta; diff --git a/packages/accessible-chat/tsconfig.json b/packages/accessible-chat/tsconfig.json deleted file mode 100644 index 15d0c1cab..000000000 --- a/packages/accessible-chat/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "files": [], - "compilerOptions": { - "jsx": "react" - }, - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - }, - { - "path": "./tsconfig.spec.json" - }, - { - "path": "./.storybook/tsconfig.json" - } - ] -} diff --git a/packages/accessible-chat/tsconfig.lib.json b/packages/accessible-chat/tsconfig.lib.json deleted file mode 100644 index b331bf1ff..000000000 --- a/packages/accessible-chat/tsconfig.lib.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "declaration": true, - "types": ["node"] - }, - "include": ["src/**/*.ts"], - "exclude": [ - "jest.config.ts", - "src/**/*.test.ts", - "src/**/*.test.tsx", - "files/**", - "**/*.stories.ts", - "**/*.stories.js", - "**/*.stories.jsx", - "**/*.stories.tsx" - ] -} diff --git a/packages/accessible-chat/tsconfig.spec.json b/packages/accessible-chat/tsconfig.spec.json deleted file mode 100644 index 361fd5a7e..000000000 --- a/packages/accessible-chat/tsconfig.spec.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "module": "commonjs", - "types": ["jest", "node"] - }, - "include": [ - "jest.config.ts", - "src/**/*.test.ts", - "src/**/*.test.tsx", - "src/**/*.d.ts" - ] -} diff --git a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx b/packages/react-chat/stories/Chat/AccessibleChat.stories.tsx similarity index 93% rename from packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx rename to packages/react-chat/stories/Chat/AccessibleChat.stories.tsx index a98681fab..07871d678 100644 --- a/packages/accessible-chat/src/components/AccessibleChat/AccessibleChat.tsx +++ b/packages/react-chat/stories/Chat/AccessibleChat.stories.tsx @@ -11,8 +11,6 @@ import { ChatMyMessage, } from '@fluentui-contrib/react-chat'; -import { useStyles } from './AccessibleChat.styles'; - const ChatMessageContent = ({ id, children, ...rest }) => (
= ({ user, content }; export const AccessibleChat: React.FC = () => { - const styles = useStyles(); - const user1: User = { name: 'Ashley McCarthy', status: 'available' }; return ( -
+

Accessible chat

diff --git a/packages/react-chat/stories/Chat/index.stories.tsx b/packages/react-chat/stories/Chat/index.stories.tsx index 064c57cc5..96a47c8da 100644 --- a/packages/react-chat/stories/Chat/index.stories.tsx +++ b/packages/react-chat/stories/Chat/index.stories.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { Meta } from '@storybook/react'; import { Chat } from '@fluentui-contrib/react-chat'; export { Default } from './Default.stories'; +export { AccessibleChat } from './AccessibleChat.stories'; const meta: Meta = { component: Chat, From abe3df88c3cb95c561cba6c7f6426ecf9c1bb492 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Tue, 20 Jun 2023 15:08:19 +0200 Subject: [PATCH 08/29] Rename the accessible chat prototype --- ...eChat.stories.tsx => ChatWithFocusableContent.stories.tsx} | 4 ++-- packages/react-chat/stories/Chat/index.stories.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename packages/react-chat/stories/Chat/{AccessibleChat.stories.tsx => ChatWithFocusableContent.stories.tsx} (95%) diff --git a/packages/react-chat/stories/Chat/AccessibleChat.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx similarity index 95% rename from packages/react-chat/stories/Chat/AccessibleChat.stories.tsx rename to packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index 07871d678..dcecabaa1 100644 --- a/packages/react-chat/stories/Chat/AccessibleChat.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -58,12 +58,12 @@ const ExtendedChatMessage: React.FC = ({ user, content ); }; -export const AccessibleChat: React.FC = () => { +export const ChatWithFocusableContent: React.FC = () => { const user1: User = { name: 'Ashley McCarthy', status: 'available' }; return (
-

Accessible chat

+

Chat with focusable content

diff --git a/packages/react-chat/stories/Chat/index.stories.tsx b/packages/react-chat/stories/Chat/index.stories.tsx index 96a47c8da..e98b64384 100644 --- a/packages/react-chat/stories/Chat/index.stories.tsx +++ b/packages/react-chat/stories/Chat/index.stories.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { Meta } from '@storybook/react'; import { Chat } from '@fluentui-contrib/react-chat'; export { Default } from './Default.stories'; -export { AccessibleChat } from './AccessibleChat.stories'; +export { ChatWithFocusableContent } from './ChatWithFocusableContent.stories'; const meta: Meta = { component: Chat, From 52d080f424beab5744ad17ef0342c0d8127b6109 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Tue, 20 Jun 2023 15:24:30 +0200 Subject: [PATCH 09/29] Remove unused imports and add aria-readingmode attribute --- .../stories/Chat/ChatWithFocusableContent.stories.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index dcecabaa1..aa0be57b4 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -1,9 +1,7 @@ import * as React from 'react'; import { - mergeClasses, Avatar, - PresenceBadgeStatus, } from '@fluentui/react-components'; import { Chat, @@ -16,6 +14,7 @@ const ChatMessageContent = ({ id, children, ...rest }) => ( {...rest} id={id} tabIndex={0} + aria-readingmode="true" >{children}
); From dd64ea3fb25d7d8cbc52f1a89e36ddd138a457cd Mon Sep 17 00:00:00 2001 From: Lingfan Gao Date: Wed, 21 Jun 2023 07:09:11 +0000 Subject: [PATCH 10/29] cleanup fixes --- .../Chat/ChatWithFocusableContent.stories.tsx | 77 +++++++++---------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index aa0be57b4..4c97d8c98 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -1,57 +1,51 @@ import * as React from 'react'; - import { Avatar, + useFluent, + PresenceBadgeStatus, } from '@fluentui/react-components'; -import { - Chat, - ChatMessage, - ChatMyMessage, -} from '@fluentui-contrib/react-chat'; - -const ChatMessageContent = ({ id, children, ...rest }) => ( -
{children}
-); +import { Chat, ChatMessage, ChatMyMessage } from '@fluentui-contrib/react-chat'; interface User { - name; - status; + name: string; + status: PresenceBadgeStatus; } -interface ExtendedChatMessageProps { - user?; - contentId; - children; +interface CustomChatMessageProps { + user?: User; + contentId: string; + children: React.ReactNode; } -const ExtendedChatMessage: React.FC = ({ user, contentId, children, ...rest }) => { - const handleMessageKeyDown = (event) => { + +const ChatMessageContent: React.FC> = ( + props +) =>
; + +const CustomChatMessage: React.FC = ({ + user, + contentId, + children, +}) => { + const { targetDocument } = useFluent(); + const handleMessageKeyDown = (event: React.KeyboardEvent) => { if (event.ctrlKey && event.key === 'Enter') { - document.getElementById(contentId).focus(); + targetDocument?.getElementById(contentId)?.focus(); } }; return ( <> - {!user ? ( - - {children} - - ) : ( + {user ? ( } onKeyDown={handleMessageKeyDown} > {children} + ) : ( + + {children} + )} ); @@ -66,13 +60,18 @@ export const ChatWithFocusableContent: React.FC = () => { - Hello I am Ashley - Nice to meet you! - - This is my homepage. Some text goes here to demonstrate reading of longer runsof texts. Now follows another link which is also a dummy link. - + + Hello I am Ashley + + + Nice to meet you! + + + This is my homepage. Some text goes here to + demonstrate reading of longer runs of texts. Now follows{' '} + another link which is also a dummy link. + -
); }; From fc51b2b0f4f9ea710ad3ecc9f2fcc1ec321de290 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Wed, 21 Jun 2023 15:47:09 +0200 Subject: [PATCH 11/29] Replace aria- attribute withwith document role and set tabindex=0 --- .../stories/Chat/ChatWithFocusableContent.stories.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index 4c97d8c98..6af9a0cbd 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -19,7 +19,7 @@ interface CustomChatMessageProps { const ChatMessageContent: React.FC> = ( props -) =>
; +) =>
; const CustomChatMessage: React.FC = ({ user, @@ -59,7 +59,7 @@ export const ChatWithFocusableContent: React.FC = () => {

Chat with focusable content

- + Hello I am Ashley From e73f59d7197e15f29b1fe3166a5e531c600cc7db Mon Sep 17 00:00:00 2001 From: ling1726 Date: Wed, 21 Jun 2023 16:02:08 +0200 Subject: [PATCH 12/29] Update tsconfig.base.json --- tsconfig.base.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/tsconfig.base.json b/tsconfig.base.json index f208ad321..c4d223f53 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -16,9 +16,6 @@ "strict": true, "baseUrl": ".", "paths": { - "@fluentui-contrib/accessible-chat": [ - "packages/accessible-chat/src/index.ts" - ], "@fluentui-contrib/nx-plugin": ["packages/nx-plugin/src/index.ts"], "@fluentui-contrib/react-chat": ["packages/react-chat/src/index.ts"], "@fluentui-contrib/react-shadow": ["packages/react-shadow/src/index.ts"] From cb31f4e0efff05e4dcb93917803b5b5fcc05e4a1 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Thu, 29 Jun 2023 20:16:16 +0200 Subject: [PATCH 13/29] AddChatLink component for aria-label links --- .../Chat/ChatWithFocusableContent.stories.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index 6af9a0cbd..1f559a2b8 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { Avatar, + Link, useFluent, PresenceBadgeStatus, } from '@fluentui/react-components'; @@ -19,7 +20,7 @@ interface CustomChatMessageProps { const ChatMessageContent: React.FC> = ( props -) =>
; +) =>
; const CustomChatMessage: React.FC = ({ user, @@ -51,6 +52,13 @@ const CustomChatMessage: React.FC = ({ ); }; +interface ChatLinkProps extends React.AnchorHTMLAttributes { +children: React.ReactNode; +} + +const ChatLink: React.FC = ({ children, ...props } ) => +; + export const ChatWithFocusableContent: React.FC = () => { const user1: User = { name: 'Ashley McCarthy', status: 'available' }; @@ -67,7 +75,7 @@ export const ChatWithFocusableContent: React.FC = () => { Nice to meet you! - This is my homepage. Some text goes here to + This is my homepage. Some text goes here to demonstrate reading of longer runs of texts. Now follows{' '} another link which is also a dummy link. From c4ebcff62ea35074e981d3307126afca4d523711 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Mon, 3 Jul 2023 13:39:16 +0200 Subject: [PATCH 14/29] Add timestamp, details and compose message narration using aria-labelledby --- .../Chat/ChatWithFocusableContent.stories.tsx | 59 ++++++++++++++++--- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index 1f559a2b8..a78d51807 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -1,20 +1,28 @@ import * as React from 'react'; import { Avatar, + useId, Link, useFluent, PresenceBadgeStatus, } from '@fluentui/react-components'; -import { Chat, ChatMessage, ChatMyMessage } from '@fluentui-contrib/react-chat'; +import { + Chat, + ChatMessage, + ChatMessageProps, + ChatMyMessageProps, + ChatMyMessage, +} from '@fluentui-contrib/react-chat'; interface User { name: string; status: PresenceBadgeStatus; } -interface CustomChatMessageProps { +type CustomChatMessageProps = ChatMessageProps & ChatMyMessageProps & { user?: User; - contentId: string; + customTimestamp?: string; + customDetails?: string; children: React.ReactNode; } @@ -24,9 +32,28 @@ const ChatMessageContent: React.FC> = ( const CustomChatMessage: React.FC = ({ user, - contentId, + customTimestamp, + customDetails, children, + ...props }) => { + const messageId = useId('message'); + const contentId = `${messageId}-content`; + const timestampId = `${messageId}-timestamp`; + const detailsId = `${messageId}-details`; + + const customProps = { + timestamp: customTimestamp ? { + children: customTimestamp, + id: timestampId, + } : undefined, + details: customDetails? { + children: customDetails, + id: detailsId, + } : undefined, + 'aria-labelledby': `${contentId} ${timestampId} ${detailsId}`, + }; + const { targetDocument } = useFluent(); const handleMessageKeyDown = (event: React.KeyboardEvent) => { if (event.ctrlKey && event.key === 'Enter') { @@ -40,11 +67,18 @@ const CustomChatMessage: React.FC = ({ } onKeyDown={handleMessageKeyDown} + {...customProps} + {...props} > {children} ) : ( - + {children} )} @@ -68,13 +102,22 @@ export const ChatWithFocusableContent: React.FC = () => { - + Hello I am Ashley - + Nice to meet you! - + This is my homepage. Some text goes here to demonstrate reading of longer runs of texts. Now follows{' '} another link which is also a dummy link. From ab7f05062ee00321f6fd41199ab745bd39c81096 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Mon, 3 Jul 2023 15:02:29 +0200 Subject: [PATCH 15/29] Add message reactions --- .../Chat/ChatWithFocusableContent.stories.tsx | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index a78d51807..062c423f1 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { Avatar, + Button, useId, Link, useFluent, @@ -13,25 +14,48 @@ import { ChatMyMessageProps, ChatMyMessage, } from '@fluentui-contrib/react-chat'; +import { + EmojiSmileSlightRegular, + Question20Regular, +} from '@fluentui/react-icons'; interface User { name: string; status: PresenceBadgeStatus; } +const ChatMessageContent: React.FC> = ( + props +) =>
; + +interface ReactionsProps { +id: string; +} +const Message1Reactions: React.FC = ({ id }) => { + return ( + + ); +}; + type CustomChatMessageProps = ChatMessageProps & ChatMyMessageProps & { user?: User; + CustomReactions?: React.FC; customTimestamp?: string; customDetails?: string; children: React.ReactNode; -} - -const ChatMessageContent: React.FC> = ( - props -) =>
; - +}; const CustomChatMessage: React.FC = ({ user, + CustomReactions, customTimestamp, customDetails, children, @@ -39,10 +63,12 @@ const CustomChatMessage: React.FC = ({ }) => { const messageId = useId('message'); const contentId = `${messageId}-content`; + const reactionsId = `${messageId}-reactions`; const timestampId = `${messageId}-timestamp`; const detailsId = `${messageId}-details`; const customProps = { + reactions: CustomReactions? : undefined, timestamp: customTimestamp ? { children: customTimestamp, id: timestampId, @@ -51,7 +77,7 @@ const CustomChatMessage: React.FC = ({ children: customDetails, id: detailsId, } : undefined, - 'aria-labelledby': `${contentId} ${timestampId} ${detailsId}`, + 'aria-labelledby': `${contentId} ${reactionsId} ${timestampId} ${detailsId}`, }; const { targetDocument } = useFluent(); @@ -104,6 +130,7 @@ export const ChatWithFocusableContent: React.FC = () => { Hello I am Ashley From 3180584f3d48f26df876be884969c9a13df106f0 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Mon, 3 Jul 2023 15:22:39 +0200 Subject: [PATCH 16/29] Reaction text change --- .../stories/Chat/ChatWithFocusableContent.stories.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index 062c423f1..06b2eae60 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -16,7 +16,6 @@ import { } from '@fluentui-contrib/react-chat'; import { EmojiSmileSlightRegular, - Question20Regular, } from '@fluentui/react-icons'; interface User { @@ -39,7 +38,7 @@ const Message1Reactions: React.FC = ({ id }) => { children: , }} appearance="subtle" - aria-label="Smile" + aria-label="1 Smile reaction." > 1 From 59e9a0a7d7cafc2bdfdaa8352400e174c7489399 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Tue, 4 Jul 2023 10:33:41 +0200 Subject: [PATCH 17/29] Refactor chat message --- .../Chat/ChatWithFocusableContent.stories.tsx | 86 ++++++++++++------- 1 file changed, 54 insertions(+), 32 deletions(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index 06b2eae60..87ea3e219 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -2,6 +2,10 @@ import * as React from 'react'; import { Avatar, Button, + Popover, + PopoverProps, + PopoverSurface, + PopoverTrigger, useId, Link, useFluent, @@ -14,10 +18,13 @@ import { ChatMyMessageProps, ChatMyMessage, } from '@fluentui-contrib/react-chat'; + import { EmojiSmileSlightRegular, } from '@fluentui/react-icons'; +import { useTabsterAttributes } from '@fluentui/react-tabster'; + interface User { name: string; status: PresenceBadgeStatus; @@ -46,6 +53,7 @@ const Message1Reactions: React.FC = ({ id }) => { }; type CustomChatMessageProps = ChatMessageProps & ChatMyMessageProps & { + id: string; user?: User; CustomReactions?: React.FC; customTimestamp?: string; @@ -53,6 +61,7 @@ type CustomChatMessageProps = ChatMessageProps & ChatMyMessageProps & { children: React.ReactNode; }; const CustomChatMessage: React.FC = ({ + id, user, CustomReactions, customTimestamp, @@ -60,54 +69,64 @@ const CustomChatMessage: React.FC = ({ children, ...props }) => { + const [popoverOpen, setPopoverOpen] = React.useState(false); const messageId = useId('message'); const contentId = `${messageId}-content`; const reactionsId = `${messageId}-reactions`; const timestampId = `${messageId}-timestamp`; const detailsId = `${messageId}-details`; - - const customProps = { - reactions: CustomReactions? : undefined, - timestamp: customTimestamp ? { - children: customTimestamp, - id: timestampId, - } : undefined, - details: customDetails? { - children: customDetails, - id: detailsId, - } : undefined, - 'aria-labelledby': `${contentId} ${reactionsId} ${timestampId} ${detailsId}`, - }; + const ChatMessageType = user ? ChatMessage : ChatMyMessage; + + const handlePopoverOpenChange: PopoverProps['onOpenChange'] = (event, { open }) => + setPopoverOpen(open); const { targetDocument } = useFluent(); - const handleMessageKeyDown = (event: React.KeyboardEvent) => { + const handleChatMessageKeyDown = (event: React.KeyboardEvent) => { if (event.ctrlKey && event.key === 'Enter') { targetDocument?.getElementById(contentId)?.focus(); } }; + const handleChatMessageFocus = React.useCallback(() => + setPopoverOpen(true), + []); + + const modalizerAttributes = useTabsterAttributes({ + modalizer: { + id, + isOthersAccessible: true, + isAlwaysAccessible: true, + isTrapped: true, + }, + }); + return ( - <> - {user ? ( - } - onKeyDown={handleMessageKeyDown} - {...customProps} + + + : undefined} + reactions={CustomReactions? : undefined} + timestamp={customTimestamp ? {children: customTimestamp, id: timestampId} : undefined} + details={customDetails? {children: customDetails, id: detailsId} : undefined} + onKeyDown={handleChatMessageKeyDown} + onFocus={handleChatMessageFocus} + aria-labelledby={`${contentId} ${reactionsId} ${timestampId} ${detailsId}`} {...props} + {...modalizerAttributes} > {children} - - ) : ( - - {children} - - )} - + + + + + + + ); }; @@ -128,6 +147,7 @@ export const ChatWithFocusableContent: React.FC = () => { { Hello I am Ashley Nice to meet you! From 5245d4241bbdb00e009c2e097ac4499afed00d8d Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Tue, 4 Jul 2023 13:40:50 +0200 Subject: [PATCH 18/29] Fix chat message actions entering --- .../Chat/ChatWithFocusableContent.stories.tsx | 51 ++++++++++++------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index 87ea3e219..4e17bbf0d 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -53,7 +53,6 @@ const Message1Reactions: React.FC = ({ id }) => { }; type CustomChatMessageProps = ChatMessageProps & ChatMyMessageProps & { - id: string; user?: User; CustomReactions?: React.FC; customTimestamp?: string; @@ -61,7 +60,6 @@ type CustomChatMessageProps = ChatMessageProps & ChatMyMessageProps & { children: React.ReactNode; }; const CustomChatMessage: React.FC = ({ - id, user, CustomReactions, customTimestamp, @@ -70,34 +68,49 @@ const CustomChatMessage: React.FC = ({ ...props }) => { const [popoverOpen, setPopoverOpen] = React.useState(false); + const messageId = useId('message'); const contentId = `${messageId}-content`; const reactionsId = `${messageId}-reactions`; const timestampId = `${messageId}-timestamp`; const detailsId = `${messageId}-details`; + const popoverSurfaceId = `${messageId}-popover-surface`; const ChatMessageType = user ? ChatMessage : ChatMyMessage; - + + const messageRef = React.useRef(null); + const firstButtonInPopoverRef = React.useRef(null); + const isPopoverOpenFromKeyDown = React.useRef(false); + + React.useEffect(() => { + if (popoverOpen && isPopoverOpenFromKeyDown.current) { + isPopoverOpenFromKeyDown.current = false; + firstButtonInPopoverRef.current?.focus(); + } + }, [popoverOpen]); + const handlePopoverOpenChange: PopoverProps['onOpenChange'] = (event, { open }) => setPopoverOpen(open); const { targetDocument } = useFluent(); const handleChatMessageKeyDown = (event: React.KeyboardEvent) => { + if (event.key === 'Enter' && event.target === messageRef.current) { + isPopoverOpenFromKeyDown.current = true; + } if (event.ctrlKey && event.key === 'Enter') { targetDocument?.getElementById(contentId)?.focus(); } }; - const handleChatMessageFocus = React.useCallback(() => - setPopoverOpen(true), - []); - const modalizerAttributes = useTabsterAttributes({ modalizer: { - id, + id: messageId, isOthersAccessible: true, isAlwaysAccessible: true, isTrapped: true, }, + focusable: { + ignoreKeydown: { Enter: true }, + }, }); return ( @@ -109,22 +122,29 @@ const CustomChatMessage: React.FC = ({ > : undefined} reactions={CustomReactions? : undefined} timestamp={customTimestamp ? {children: customTimestamp, id: timestampId} : undefined} details={customDetails? {children: customDetails, id: detailsId} : undefined} onKeyDown={handleChatMessageKeyDown} - onFocus={handleChatMessageFocus} + {...(popoverOpen && { 'aria-owns': popoverSurfaceId })} aria-labelledby={`${contentId} ${reactionsId} ${timestampId} ${detailsId}`} + aria-expanded={undefined} {...props} - {...modalizerAttributes} > {children} - - - + + + ); @@ -143,11 +163,10 @@ export const ChatWithFocusableContent: React.FC = () => { return (

Chat with focusable content

- + { Hello I am Ashley Nice to meet you! From afd3e168a969b06e83022a6333f0c8af8bf527ec Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Tue, 4 Jul 2023 15:28:21 +0200 Subject: [PATCH 19/29] Fix Control + Enter message content focusing --- .../utils/useChatMessageFocusableGroup.ts | 61 ++++++++++++++++++- .../Chat/ChatWithFocusableContent.stories.tsx | 13 ++-- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/packages/react-chat/src/components/utils/useChatMessageFocusableGroup.ts b/packages/react-chat/src/components/utils/useChatMessageFocusableGroup.ts index 61195af25..8373a472d 100644 --- a/packages/react-chat/src/components/utils/useChatMessageFocusableGroup.ts +++ b/packages/react-chat/src/components/utils/useChatMessageFocusableGroup.ts @@ -1,4 +1,6 @@ +import * as React from 'react'; import { useFocusableGroup } from '@fluentui/react-tabster'; +import { Types as TabsterTypes } from 'tabster'; import { ChatMessageState } from '../ChatMessage/ChatMessage.types'; import { ChatMyMessageState } from '../ChatMyMessage/ChatMyMessage.types'; @@ -9,6 +11,61 @@ export const useChatMessageFocusableGroup = ( tabBehavior: 'limited-trap-focus', }); - (state.body as Record)['data-tabster'] = - groupperAttributes['data-tabster']; + // TODO: type cast here due to state.body not supporting data-xxx type. + // Need typescript 4.4+ (Feature 2759283) and fluent Slot typing update (https://github.com/microsoft/fluentui/issues/23033) + const consumerTabsterAttributesValue = (state.body as Record)[ + TabsterTypes.TabsterAttributeName + ]; + + // merge default Tabster attributes with consumer's Tabster attributes + const finalTabsterAttributes = useMergedTabsterAttributes( + groupperAttributes, + consumerTabsterAttributesValue + ? { [TabsterTypes.TabsterAttributeName]: consumerTabsterAttributesValue } + : undefined + ); + + (state.body as Record)[ + TabsterTypes.TabsterAttributeName + ] = finalTabsterAttributes[TabsterTypes.TabsterAttributeName]; +}; + +/** + * Merge two tabster attributes (object of type {"data-tabster": string}) and return the result. + */ +const useMergedTabsterAttributes: ( + attributeOne: TabsterTypes.TabsterDOMAttribute, + attributeTwo?: TabsterTypes.TabsterDOMAttribute +) => TabsterTypes.TabsterDOMAttribute = (attributeOne, attributeTwo) => { + const attributeOneValueString = + attributeOne[TabsterTypes.TabsterAttributeName]; + const attributeTwoValueString = + attributeTwo?.[TabsterTypes.TabsterAttributeName]; + + return React.useMemo(() => { + let attributeOneValue = {}; + let attributeTwoValue = {}; + if (attributeOneValueString) { + try { + attributeOneValue = JSON.parse(attributeOneValueString); + } catch (e) { + attributeOneValue = {}; + } + } + if (attributeTwoValueString) { + try { + attributeTwoValue = JSON.parse(attributeTwoValueString); + } catch (e) { + attributeTwoValue = {}; + } + } + return { + [TabsterTypes.TabsterAttributeName]: attributeTwoValueString + ? JSON.stringify({ + ...attributeOneValue, + ...attributeTwoValue, + }) + : attributeOneValueString, + }; + }, [attributeOneValueString, attributeTwoValueString]); }; diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index 4e17bbf0d..6c28d00da 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -8,7 +8,6 @@ import { PopoverTrigger, useId, Link, - useFluent, PresenceBadgeStatus, } from '@fluentui/react-components'; import { @@ -78,6 +77,7 @@ const CustomChatMessage: React.FC = ({ const ChatMessageType = user ? ChatMessage : ChatMyMessage; const messageRef = React.useRef(null); + const messageContentRef = React.useRef(null); const firstButtonInPopoverRef = React.useRef(null); const isPopoverOpenFromKeyDown = React.useRef(false); @@ -91,13 +91,14 @@ const CustomChatMessage: React.FC = ({ const handlePopoverOpenChange: PopoverProps['onOpenChange'] = (event, { open }) => setPopoverOpen(open); - const { targetDocument } = useFluent(); const handleChatMessageKeyDown = (event: React.KeyboardEvent) => { - if (event.key === 'Enter' && event.target === messageRef.current) { + if (event.key === 'Enter') { + if (event.ctrlKey) { + messageContentRef.current?.focus(); + // targetDocument?.getElementById(contentId)?.focus(); + }else if (event.target === messageRef.current) { isPopoverOpenFromKeyDown.current = true; } - if (event.ctrlKey && event.key === 'Enter') { - targetDocument?.getElementById(contentId)?.focus(); } }; @@ -136,7 +137,7 @@ const CustomChatMessage: React.FC = ({ aria-expanded={undefined} {...props} > - {children} + {children} Date: Tue, 4 Jul 2023 16:12:58 +0200 Subject: [PATCH 20/29] Use refs instead of getElementById --- .../stories/Chat/ChatWithFocusableContent.stories.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index 6c28d00da..e72a6cfc9 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -29,9 +29,8 @@ interface User { status: PresenceBadgeStatus; } -const ChatMessageContent: React.FC> = ( - props -) =>
; +const ChatMessageContent = React.forwardRef>((props, ref) => +
); interface ReactionsProps { id: string; From 579bd77d2e59a885ccbf9566c63cafa06b27b407 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Tue, 4 Jul 2023 16:58:11 +0200 Subject: [PATCH 21/29] Add toolbars into popover surface --- .../Chat/ChatWithFocusableContent.stories.tsx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index e72a6cfc9..29667ad1d 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -2,12 +2,13 @@ import * as React from 'react'; import { Avatar, Button, + Link, Popover, PopoverProps, PopoverSurface, PopoverTrigger, + Toolbar, useId, - Link, PresenceBadgeStatus, } from '@fluentui/react-components'; import { @@ -43,6 +44,7 @@ const Message1Reactions: React.FC = ({ id }) => { children: , }} appearance="subtle" + tabIndex={-1} aria-label="1 Smile reaction." > 1 @@ -143,8 +145,17 @@ const CustomChatMessage: React.FC = ({ {...modalizerAttributes} id={popoverSurfaceId} > - - + + + + + + + + + + + ); From ac9232e64d2a367e16ab8ad1c9b3b9e77af1cbd3 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Tue, 4 Jul 2023 17:49:55 +0200 Subject: [PATCH 22/29] Use document role for chat message contents --- .../stories/Chat/ChatWithFocusableContent.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index 29667ad1d..c32d063c8 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -31,7 +31,7 @@ interface User { } const ChatMessageContent = React.forwardRef>((props, ref) => -
); +
); interface ReactionsProps { id: string; From 79f2e747d1a6a6ecb052bb8e49f34c44a0f27e40 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Thu, 13 Jul 2023 17:37:26 +0200 Subject: [PATCH 23/29] move application role to the top level div --- .../src/components/utils/useChatMessageFocusableGroup.ts | 4 +++- .../stories/Chat/ChatWithFocusableContent.stories.tsx | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/react-chat/src/components/utils/useChatMessageFocusableGroup.ts b/packages/react-chat/src/components/utils/useChatMessageFocusableGroup.ts index 928090497..8373a472d 100644 --- a/packages/react-chat/src/components/utils/useChatMessageFocusableGroup.ts +++ b/packages/react-chat/src/components/utils/useChatMessageFocusableGroup.ts @@ -1,4 +1,6 @@ -import { useFocusableGroup } from '@fluentui/react-components'; +import * as React from 'react'; +import { useFocusableGroup } from '@fluentui/react-tabster'; +import { Types as TabsterTypes } from 'tabster'; import { ChatMessageState } from '../ChatMessage/ChatMessage.types'; import { ChatMyMessageState } from '../ChatMyMessage/ChatMyMessage.types'; diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index c32d063c8..8a8f804f9 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -172,11 +172,11 @@ export const ChatWithFocusableContent: React.FC = () => { const user1: User = { name: 'Ashley McCarthy', status: 'available' }; return ( -
+

Chat with focusable content

- + Date: Thu, 13 Jul 2023 18:51:58 +0200 Subject: [PATCH 24/29] Move h1 heading outside from the application role --- .../stories/Chat/ChatWithFocusableContent.stories.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index 8a8f804f9..b298d4dc9 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -172,8 +172,9 @@ export const ChatWithFocusableContent: React.FC = () => { const user1: User = { name: 'Ashley McCarthy', status: 'available' }; return ( -
+ <>

Chat with focusable content

+
@@ -200,5 +201,6 @@ export const ChatWithFocusableContent: React.FC = () => {
+ ); }; From 059ba30c8549deb208e4b1d94e5c1456c062749f Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Tue, 18 Jul 2023 15:21:20 +0200 Subject: [PATCH 25/29] Make chat message content texts longer --- .../stories/Chat/ChatWithFocusableContent.stories.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index b298d4dc9..06ec3ae46 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -183,7 +183,7 @@ export const ChatWithFocusableContent: React.FC = () => { CustomReactions={Message1Reactions} customTimestamp="June 20, 2023 9:35 AM." > - Hello I am Ashley + Hello I am Ashley. This is a long message content which we would like to read in the document screen reader mode. NVDA already implements some support for the automatic switching of the mode when an element with the "document" role or its descendant is focused, and when it is contained within an element with the "application" role, but is stil not yet at the stage we would be satisfied with. Therefore, we hope to achieve the desired behavior first with JAWS. Once implemented, this will significantly ease the reading of long messages or even enable text selection. This will also solve the issue with JAWS which trims long messages. { user={user1} customTimestamp="Today at 5:22 PM." > - This is my homepage. Some text goes here to - demonstrate reading of longer runs of texts. Now follows{' '} + This is my homepage. Some text goes here to + further demonstrate reading of longer runs of texts. To make an example of an interactive element within a message, now follows{' '} another link which is also a dummy link. From 964136a5eb6c744e474375499b3e1b75164dd6c1 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Tue, 18 Jul 2023 19:23:27 +0200 Subject: [PATCH 26/29] Move application role closer to document role and use aria-roledescription --- .../stories/Chat/ChatWithFocusableContent.stories.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index 06ec3ae46..b14a6684d 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -31,7 +31,9 @@ interface User { } const ChatMessageContent = React.forwardRef>((props, ref) => -
); +
+
+
); interface ReactionsProps { id: string; @@ -174,7 +176,7 @@ export const ChatWithFocusableContent: React.FC = () => { return ( <>

Chat with focusable content

-
+
From 2088511989c6c752514520a823600462d7f77bb4 Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Wed, 19 Jul 2023 18:47:49 +0200 Subject: [PATCH 27/29] Move application role back to top level and change message texts" --- .../stories/Chat/ChatWithFocusableContent.stories.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index b14a6684d..ce71efb17 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -31,7 +31,7 @@ interface User { } const ChatMessageContent = React.forwardRef>((props, ref) => -
+
); @@ -176,7 +176,8 @@ export const ChatWithFocusableContent: React.FC = () => { return ( <>

Chat with focusable content

-
+
+ @@ -185,7 +186,7 @@ export const ChatWithFocusableContent: React.FC = () => { CustomReactions={Message1Reactions} customTimestamp="June 20, 2023 9:35 AM." > - Hello I am Ashley. This is a long message content which we would like to read in the document screen reader mode. NVDA already implements some support for the automatic switching of the mode when an element with the "document" role or its descendant is focused, and when it is contained within an element with the "application" role, but is stil not yet at the stage we would be satisfied with. Therefore, we hope to achieve the desired behavior first with JAWS. Once implemented, this will significantly ease the reading of long messages or even enable text selection. This will also solve the issue with JAWS which trims long messages. + Hello I am Ashley. This is an examplary long message content which we would like to read in the document screen reader mode. NVDA already implements sufficient support for the automatic switching of the screen reader mode when an element with the "document" role or its descendant is focused or when explicitly enabled by the user, and when it is contained within an element with the "application" role. However, JAWS does not yet behave as we would expect to, therefore, we hope to achieve the desired behavior also with JAWS. Once implemented, this will significantly ease the reading of long messages or even enable convenient text selection. This will also solve the issue with JAWS which trims long messages to a certain character limit. Date: Tue, 25 Jul 2023 11:41:39 +0200 Subject: [PATCH 28/29] Add missing visual link texts --- .../stories/Chat/ChatWithFocusableContent.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index ce71efb17..90d1204fb 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -168,7 +168,7 @@ children: React.ReactNode; } const ChatLink: React.FC = ({ children, ...props } ) => -; +{children}; export const ChatWithFocusableContent: React.FC = () => { const user1: User = { name: 'Ashley McCarthy', status: 'available' }; From 08e804f856e9afc968c971c9cc937008dcdadf2b Mon Sep 17 00:00:00 2001 From: Adam Samec Date: Mon, 28 Aug 2023 13:34:58 +0200 Subject: [PATCH 29/29] Add srLabel prop for ChatLink instead of children.toString() and replace with --- .../Chat/ChatWithFocusableContent.stories.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx index 90d1204fb..57c55ca20 100644 --- a/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx +++ b/packages/react-chat/stories/Chat/ChatWithFocusableContent.stories.tsx @@ -128,7 +128,7 @@ const CustomChatMessage: React.FC = ({ : undefined} reactions={CustomReactions? : undefined} @@ -164,11 +164,12 @@ const CustomChatMessage: React.FC = ({ }; interface ChatLinkProps extends React.AnchorHTMLAttributes { + srLabel:string; children: React.ReactNode; } -const ChatLink: React.FC = ({ children, ...props } ) => -{children}; +const ChatLink: React.FC = ({ srLabel, children, ...props } ) => +{children}; export const ChatWithFocusableContent: React.FC = () => { const user1: User = { name: 'Ashley McCarthy', status: 'available' }; @@ -198,9 +199,9 @@ export const ChatWithFocusableContent: React.FC = () => { user={user1} customTimestamp="Today at 5:22 PM." > - This is my homepage. Some text goes here to - further demonstrate reading of longer runs of texts. To make an example of an interactive element within a message, now follows{' '} - another link which is also a dummy link. + This is my homepage. Some text goes here to + further demonstrate reading of longer runs of texts. To make an example of another interactive element within a message, now follows{' '} + another link which is also a dummy link.