snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
This commit is contained in:
3
packages/ui-composer/.storybook/main.ts
Normal file
3
packages/ui-composer/.storybook/main.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import baseConfig from '@rocket.chat/storybook-config/main';
|
||||
|
||||
export default baseConfig();
|
||||
11
packages/ui-composer/.storybook/preview.tsx
Normal file
11
packages/ui-composer/.storybook/preview.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { parameters, decorators } from '@rocket.chat/storybook-config/preview';
|
||||
import type { Preview } from '@storybook/react';
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
...parameters,
|
||||
},
|
||||
decorators: [...decorators],
|
||||
};
|
||||
|
||||
export default preview;
|
||||
289
packages/ui-composer/CHANGELOG.md
Normal file
289
packages/ui-composer/CHANGELOG.md
Normal file
@@ -0,0 +1,289 @@
|
||||
# @rocket.chat/ui-composer
|
||||
|
||||
## 5.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- <details><summary>Updated dependencies [4947601bbf042cd1b2385f8f5dda438e608faea7, 742009a09148e33d141f50691cdec0f7e9818535]:</summary>
|
||||
|
||||
- @rocket.chat/ui-client@34.0.0
|
||||
</details>
|
||||
|
||||
## 5.0.0-rc.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- <details><summary>Updated dependencies [4947601bbf042cd1b2385f8f5dda438e608faea7, 742009a09148e33d141f50691cdec0f7e9818535]:</summary>
|
||||
|
||||
- @rocket.chat/ui-client@34.0.0-rc.0
|
||||
</details>
|
||||
|
||||
## 4.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- <details><summary>Updated dependencies [4b57346a59b5c9433c25845c886be11af1bf71d4]:</summary>
|
||||
|
||||
- @rocket.chat/ui-client@33.0.0
|
||||
</details>
|
||||
|
||||
## 4.0.0-rc.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- <details><summary>Updated dependencies [4b57346a59b5c9433c25845c886be11af1bf71d4]:</summary>
|
||||
|
||||
- @rocket.chat/ui-client@33.0.0-rc.0
|
||||
</details>
|
||||
|
||||
## 3.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- <details><summary>Updated dependencies []:</summary>
|
||||
|
||||
- @rocket.chat/ui-client@32.0.0
|
||||
</details>
|
||||
|
||||
## 3.0.0-rc.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- <details><summary>Updated dependencies []:</summary>
|
||||
|
||||
- @rocket.chat/ui-client@32.0.0-rc.0
|
||||
</details>
|
||||
|
||||
## 2.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- <details><summary>Updated dependencies [fac64728505b312d5da786e92d3134450ce4a7c1]:</summary>
|
||||
|
||||
- @rocket.chat/ui-client@31.0.0
|
||||
</details>
|
||||
|
||||
## 2.0.0-rc.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- <details><summary>Updated dependencies [fac64728505b312d5da786e92d3134450ce4a7c1]:</summary>
|
||||
|
||||
- @rocket.chat/ui-client@31.0.0-rc.0
|
||||
</details>
|
||||
|
||||
## 1.0.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ([#40181](https://github.com/RocketChat/Rocket.Chat/pull/40181)) Adds file thumbnails with image preview to the message composer attachments
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- <details><summary>Updated dependencies [543b6c8cbde0d084a3a923acf4845b68db80206a]:</summary>
|
||||
|
||||
- @rocket.chat/ui-client@30.0.0
|
||||
</details>
|
||||
|
||||
## 1.0.0-rc.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- <details><summary>Updated dependencies []:</summary>
|
||||
|
||||
- @rocket.chat/ui-client@30.0.0-rc.2
|
||||
</details>
|
||||
|
||||
## 1.0.0-rc.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- <details><summary>Updated dependencies []:</summary>
|
||||
|
||||
- @rocket.chat/ui-client@30.0.0-rc.1
|
||||
</details>
|
||||
|
||||
## 1.0.0-rc.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ([#40181](https://github.com/RocketChat/Rocket.Chat/pull/40181)) Adds file thumbnails with image preview to the message composer attachments
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- <details><summary>Updated dependencies [543b6c8cbde0d084a3a923acf4845b68db80206a]:</summary>
|
||||
|
||||
- @rocket.chat/ui-client@30.0.0-rc.0
|
||||
</details>
|
||||
|
||||
## 0.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ([#39425](https://github.com/RocketChat/Rocket.Chat/pull/39425)) Adds support for multiple files in message composer, improving file upload experience
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#38989](https://github.com/RocketChat/Rocket.Chat/pull/38989)) chore(eslint): Upgrades ESLint and its configuration
|
||||
|
||||
## 0.6.0-rc.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ([#39425](https://github.com/RocketChat/Rocket.Chat/pull/39425)) Adds support for multiple files in message composer, improving file upload experience
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#38989](https://github.com/RocketChat/Rocket.Chat/pull/38989)) chore(eslint): Upgrades ESLint and its configuration
|
||||
|
||||
## 0.5.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#36207](https://github.com/RocketChat/Rocket.Chat/pull/36207)) Introduces the Outbound Message feature to Omnichannel, allowing organizations to initiate proactive communication with contacts through their preferred messaging channel directly from Rocket.Chat
|
||||
|
||||
## 0.5.3-rc.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#36207](https://github.com/RocketChat/Rocket.Chat/pull/36207)) Introduces the Outbound Message feature to Omnichannel, allowing organizations to initiate proactive communication with contacts through their preferred messaging channel directly from Rocket.Chat
|
||||
|
||||
## 0.5.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#35286](https://github.com/RocketChat/Rocket.Chat/pull/35286)) Bumps fuselage and related packages versions to use the most recent releases of each package, especially the fix for the missing track of the fuselage slider component
|
||||
|
||||
## 0.5.2-rc.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#35286](https://github.com/RocketChat/Rocket.Chat/pull/35286)) Bumps fuselage and related packages versions to use the most recent releases of each package, especially the fix for the missing track of the fuselage slider component
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#34858](https://github.com/RocketChat/Rocket.Chat/pull/34858)) Fixes an issue that prevented the apps-engine from reestablishing communications with subprocesses in some cases
|
||||
|
||||
## 0.5.1-rc.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#34858](https://github.com/RocketChat/Rocket.Chat/pull/34858)) Fixes an issue that prevented the apps-engine from reestablishing communications with subprocesses in some cases
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ([#34076](https://github.com/RocketChat/Rocket.Chat/pull/34076)) Introduces a new option when exporting messages, allowing users to select and download a JSON file directly from client
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#34205](https://github.com/RocketChat/Rocket.Chat/pull/34205)) Fixes an error where the engine would not retry a subprocess restart if the last attempt failed
|
||||
|
||||
- ([#34858](https://github.com/RocketChat/Rocket.Chat/pull/34858)) Fixes an issue that prevented the apps-engine from reestablishing communications with subprocesses in some cases
|
||||
|
||||
- ([#34205](https://github.com/RocketChat/Rocket.Chat/pull/34205)) Fixes error propagation when trying to get the status of apps in some cases
|
||||
|
||||
- ([#34205](https://github.com/RocketChat/Rocket.Chat/pull/34205)) Fixes wrong data being reported to total failed apps metrics and statistics
|
||||
|
||||
## 0.5.0-rc.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#34858](https://github.com/RocketChat/Rocket.Chat/pull/34858)) Fixes an issue that prevented the apps-engine from reestablishing communications with subprocesses in some cases
|
||||
|
||||
## 0.5.0-rc.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ([#34076](https://github.com/RocketChat/Rocket.Chat/pull/34076)) Introduces a new option when exporting messages, allowing users to select and download a JSON file directly from client
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#34205](https://github.com/RocketChat/Rocket.Chat/pull/34205)) Fixes an error where the engine would not retry a subprocess restart if the last attempt failed
|
||||
|
||||
- ([#34205](https://github.com/RocketChat/Rocket.Chat/pull/34205)) Fixes error propagation when trying to get the status of apps in some cases
|
||||
|
||||
- ([#34205](https://github.com/RocketChat/Rocket.Chat/pull/34205)) Fixes wrong data being reported to total failed apps metrics and statistics
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ([#33592](https://github.com/RocketChat/Rocket.Chat/pull/33592)) Adds ability to collapse/expand sidebar groups
|
||||
|
||||
- ([#33283](https://github.com/RocketChat/Rocket.Chat/pull/33283)) Adds a warning to inform users they are about to send unencrypted messages in an E2E Encrypted room if they have the `Unencrypted messages in encrypted rooms` setting enabled.
|
||||
|
||||
## 0.4.0-rc.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ([#33592](https://github.com/RocketChat/Rocket.Chat/pull/33592)) Adds ability to collapse/expand sidebar groups
|
||||
|
||||
- ([#33283](https://github.com/RocketChat/Rocket.Chat/pull/33283)) Adds a warning to inform users they are about to send unencrypted messages in an E2E Encrypted room if they have the `Unencrypted messages in encrypted rooms` setting enabled.
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ([#32821](https://github.com/RocketChat/Rocket.Chat/pull/32821)) Replaced new `SidebarV2` components under feature preview
|
||||
|
||||
## 0.3.0-rc.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ([#32821](https://github.com/RocketChat/Rocket.Chat/pull/32821)) Replaced new `SidebarV2` components under feature preview
|
||||
|
||||
## 0.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#32968](https://github.com/RocketChat/Rocket.Chat/pull/32968)) Bumped @rocket.chat/fuselage that fixes the Menu onPointerUp event behavior
|
||||
|
||||
## 0.2.1-rc.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#32968](https://github.com/RocketChat/Rocket.Chat/pull/32968)) Bumped @rocket.chat/fuselage that fixes the Menu onPointerUp event behavior
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ([#31821](https://github.com/RocketChat/Rocket.Chat/pull/31821)) New runtime for apps in the Apps-Engine based on the Deno platform
|
||||
|
||||
## 0.2.0-rc.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ([#31821](https://github.com/RocketChat/Rocket.Chat/pull/31821)) New runtime for apps in the Apps-Engine based on the Deno platform
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ([#31510](https://github.com/RocketChat/Rocket.Chat/pull/31510)) Composer keyboard navigability
|
||||
|
||||

|
||||
|
||||
- ([#31347](https://github.com/RocketChat/Rocket.Chat/pull/31347) by [@Sayan4444](https://github.com/Sayan4444)) New feature to support cancel message editing message and hints for shortcuts.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ([#31138](https://github.com/RocketChat/Rocket.Chat/pull/31138)) feat(uikit): Move `@rocket.chat/ui-kit` package to the main monorepo
|
||||
|
||||
## 0.1.0-rc.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 4c2771fd0c: Composer keyboard navigability
|
||||
|
||||

|
||||
|
||||
- e1fa2b84fb: New feature to support cancel message editing message and hints for shortcuts.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- b223cbde14: feat(uikit): Move `@rocket.chat/ui-kit` package to the main monorepo
|
||||
11
packages/ui-composer/jest.config.ts
Normal file
11
packages/ui-composer/jest.config.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import client from '@rocket.chat/jest-presets/client';
|
||||
import type { Config } from 'jest';
|
||||
|
||||
export default {
|
||||
preset: client.preset,
|
||||
setupFilesAfterEnv: [...client.setupFilesAfterEnv],
|
||||
moduleNameMapper: {
|
||||
'^react($|/.+)': '<rootDir>/../../node_modules/react$1',
|
||||
'^react-dom($|/.+)': '<rootDir>/../../node_modules/react-dom$1',
|
||||
},
|
||||
} satisfies Config;
|
||||
61
packages/ui-composer/package.json
Normal file
61
packages/ui-composer/package.json
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"name": "@rocket.chat/ui-composer",
|
||||
"version": "5.0.0",
|
||||
"private": true,
|
||||
"main": "./dist/index.js",
|
||||
"typings": "./dist/index.d.ts",
|
||||
"files": [
|
||||
"/dist"
|
||||
],
|
||||
"scripts": {
|
||||
".:build-preview-move": "mkdir -p ../../.preview/ && cp -r ./storybook-static ../../.preview/ui-composer",
|
||||
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
||||
"build-preview": "storybook build",
|
||||
"dev": "tsc -p tsconfig.build.json --watch --preserveWatchOutput",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint --fix .",
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"test": "jest",
|
||||
"testunit": "jest",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-aria/toolbar": "^3.0.0-nightly.5042",
|
||||
"@rocket.chat/emitter": "workspace:~",
|
||||
"@rocket.chat/fuselage": "^0.89.0",
|
||||
"@rocket.chat/fuselage-hooks": "^0.43.1",
|
||||
"@rocket.chat/fuselage-tokens": "^0.34.0",
|
||||
"@rocket.chat/icons": "^0.49.0",
|
||||
"@rocket.chat/jest-presets": "workspace:~",
|
||||
"@rocket.chat/mock-providers": "workspace:~",
|
||||
"@rocket.chat/storybook-config": "workspace:~",
|
||||
"@rocket.chat/tsconfig": "workspace:*",
|
||||
"@rocket.chat/ui-client": "workspace:~",
|
||||
"@storybook/react": "^9.1.20",
|
||||
"@testing-library/dom": "~10.4.1",
|
||||
"@testing-library/react": "~16.3.3",
|
||||
"@testing-library/user-event": "~14.6.6",
|
||||
"@types/jest": "~30.0.0",
|
||||
"@types/react": "~19.2.18",
|
||||
"@types/react-dom": "~19.2.5",
|
||||
"eslint": "~9.39.5",
|
||||
"jest": "~30.2.0",
|
||||
"react": "~19.2.8",
|
||||
"react-dom": "~19.2.8",
|
||||
"react-virtuoso": "~4.18.12",
|
||||
"storybook": "^9.1.20",
|
||||
"typescript": "~5.9.3",
|
||||
"webpack": "~5.104.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-aria/toolbar": "*",
|
||||
"@rocket.chat/fuselage": "*",
|
||||
"@rocket.chat/icons": "*",
|
||||
"@rocket.chat/ui-client": "34.0.0",
|
||||
"react": "*",
|
||||
"react-dom": "*"
|
||||
},
|
||||
"volta": {
|
||||
"extends": "../../package.json"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { mockAppRoot } from '@rocket.chat/mock-providers';
|
||||
import { composeStories } from '@storybook/react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { axe } from 'jest-axe';
|
||||
|
||||
import * as stories from './MessageComposer.stories';
|
||||
|
||||
const testCases = Object.values(composeStories(stories)).map((Story) => [Story.storyName || 'Story', Story]);
|
||||
|
||||
test.each(testCases)(`renders %s without crashing`, async (_storyname, Story) => {
|
||||
const { baseElement } = render(<Story />, {
|
||||
wrapper: mockAppRoot().build(),
|
||||
});
|
||||
expect(baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test.each(testCases)('%s should have no a11y violations', async (_storyname, Story) => {
|
||||
const { container } = render(<Story />);
|
||||
|
||||
const results = await axe(container);
|
||||
expect(results).toHaveNoViolations();
|
||||
});
|
||||
@@ -0,0 +1,163 @@
|
||||
import { Button, IconButton } from '@rocket.chat/fuselage';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { action } from 'storybook/actions';
|
||||
|
||||
import {
|
||||
MessageComposer,
|
||||
MessageComposerAction,
|
||||
MessageComposerToolbarActions,
|
||||
MessageComposerInput,
|
||||
MessageComposerToolbar,
|
||||
MessageComposerActionsDivider,
|
||||
MessageComposerToolbarSubmit,
|
||||
MessageComposerSkeleton,
|
||||
MessageComposerHint,
|
||||
MessageComposerInputExpandable,
|
||||
MessageComposerFile,
|
||||
MessageComposerFileGroup,
|
||||
MessageComposerFileError,
|
||||
} from '.';
|
||||
|
||||
export default {
|
||||
component: MessageComposer,
|
||||
} satisfies Meta<typeof MessageComposer>;
|
||||
|
||||
const MessageToolbarActions = () => (
|
||||
<MessageComposerToolbarActions>
|
||||
<MessageComposerAction title='emoji' icon='emoji' />
|
||||
<MessageComposerActionsDivider />
|
||||
<MessageComposerAction title='bold' icon='bold' />
|
||||
<MessageComposerAction title='italic' icon='italic' />
|
||||
<MessageComposerAction title='underline' icon='underline' />
|
||||
<MessageComposerAction title='strike' icon='strike' />
|
||||
<MessageComposerAction title='code' icon='code' />
|
||||
<MessageComposerAction title='multiline' icon='multiline' />
|
||||
<MessageComposerAction title='link' icon='link' />
|
||||
<MessageComposerAction title='katex' icon='katex' />
|
||||
<MessageComposerActionsDivider />
|
||||
<MessageComposerAction title='mic' icon='mic' />
|
||||
<MessageComposerAction title='video' icon='video' />
|
||||
<MessageComposerAction title='attachment' icon='clip' />
|
||||
<MessageComposerAction title='more' icon='plus' />
|
||||
</MessageComposerToolbarActions>
|
||||
);
|
||||
|
||||
export const Default: StoryObj<typeof MessageComposer> = {
|
||||
render: () => (
|
||||
<MessageComposer>
|
||||
<MessageComposerInput placeholder='Text' />
|
||||
<MessageComposerToolbar>
|
||||
<MessageToolbarActions />
|
||||
</MessageComposerToolbar>
|
||||
</MessageComposer>
|
||||
),
|
||||
};
|
||||
|
||||
export const Expandable: StoryObj<typeof MessageComposer> = {
|
||||
render: () => (
|
||||
<MessageComposer>
|
||||
<MessageComposerInputExpandable
|
||||
dimensions={{
|
||||
inlineSize: 400,
|
||||
blockSize: 120,
|
||||
}}
|
||||
placeholder='Type a message...'
|
||||
/>
|
||||
<MessageComposerToolbar>
|
||||
<MessageToolbarActions />
|
||||
</MessageComposerToolbar>
|
||||
</MessageComposer>
|
||||
),
|
||||
};
|
||||
|
||||
export const ToolbarActions: StoryObj<typeof MessageComposerToolbarActions> = {
|
||||
render: () => <MessageToolbarActions />,
|
||||
};
|
||||
|
||||
export const WithHints: StoryObj<typeof MessageComposer> = {
|
||||
render: () => (
|
||||
<>
|
||||
<MessageComposerHint
|
||||
icon='pencil'
|
||||
helperText={
|
||||
<>
|
||||
<strong>esc</strong> to cancel · <strong>enter</strong> to save
|
||||
</>
|
||||
}
|
||||
>
|
||||
Editing message
|
||||
</MessageComposerHint>
|
||||
<MessageComposer>
|
||||
<MessageComposerInput placeholder='Text' />
|
||||
<MessageComposerToolbar>
|
||||
<MessageToolbarActions />
|
||||
<MessageComposerToolbarSubmit>
|
||||
<MessageComposerAction aria-label='Send' icon='send' disabled={false} secondary={true} info={true} />
|
||||
</MessageComposerToolbarSubmit>
|
||||
</MessageComposerToolbar>
|
||||
</MessageComposer>
|
||||
</>
|
||||
),
|
||||
};
|
||||
|
||||
export const WithSubmit: StoryObj<typeof MessageComposer> = {
|
||||
render: () => (
|
||||
<MessageComposer>
|
||||
<MessageComposerInput placeholder='Text' />
|
||||
<MessageComposerToolbar>
|
||||
<MessageToolbarActions />
|
||||
<MessageComposerToolbarSubmit>
|
||||
<Button small>Preview</Button>
|
||||
<Button primary small>
|
||||
Send
|
||||
</Button>
|
||||
</MessageComposerToolbarSubmit>
|
||||
</MessageComposerToolbar>
|
||||
</MessageComposer>
|
||||
),
|
||||
};
|
||||
|
||||
export const WithFiles: StoryObj<typeof MessageComposer> = {
|
||||
render: () => (
|
||||
<MessageComposer>
|
||||
<MessageComposerInput placeholder='Text' />
|
||||
<MessageComposerFileGroup>
|
||||
<MessageComposerFile
|
||||
fileTitle='antique-pocket-clock-500x500.zip'
|
||||
fileSubtitle='58.33 KB - application/zip'
|
||||
fileFormat='zip'
|
||||
actionIcon={<IconButton aria-label='Close' icon='cross' mini />}
|
||||
onClick={action('click')}
|
||||
/>
|
||||
<MessageComposerFile
|
||||
disabled
|
||||
fileTitle='file.png'
|
||||
fileSubtitle='2 MB'
|
||||
fileFormat='png'
|
||||
actionIcon={<IconButton aria-label='Close' icon='cross' mini />}
|
||||
onClick={action('click')}
|
||||
/>
|
||||
<MessageComposerFileError
|
||||
fileTitle='file.png'
|
||||
fileFormat='png'
|
||||
error={new Error('Something went wrong')}
|
||||
actionIcon={<IconButton aria-label='Close' icon='cross' mini />}
|
||||
onClick={action('click')}
|
||||
/>
|
||||
</MessageComposerFileGroup>
|
||||
<MessageComposerToolbar>
|
||||
<MessageToolbarActions />
|
||||
<MessageComposerToolbarSubmit>
|
||||
<Button small>Preview</Button>
|
||||
<Button primary small>
|
||||
Send
|
||||
</Button>
|
||||
</MessageComposerToolbarSubmit>
|
||||
</MessageComposerToolbar>
|
||||
</MessageComposer>
|
||||
),
|
||||
};
|
||||
|
||||
export const Loading: StoryObj<typeof MessageComposer> = {
|
||||
render: () => <MessageComposerSkeleton />,
|
||||
};
|
||||
28
packages/ui-composer/src/MessageComposer/MessageComposer.tsx
Normal file
28
packages/ui-composer/src/MessageComposer/MessageComposer.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Box } from '@rocket.chat/fuselage';
|
||||
import type { ElementType, HTMLAttributes, ReactNode } from 'react';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
export type MessageComposerProps = Omit<HTMLAttributes<HTMLElement>, 'is'> & {
|
||||
children: ReactNode;
|
||||
is?: ElementType<any>;
|
||||
variant?: 'default' | 'error' | 'editing';
|
||||
};
|
||||
|
||||
const MessageComposer = forwardRef<HTMLElement, MessageComposerProps>(function MessageComposer({ variant, ...props }, ref) {
|
||||
return (
|
||||
<Box
|
||||
rcx-input-box__wrapper
|
||||
marginBlockStart={2}
|
||||
backgroundColor={variant === 'editing' ? 'status-background-warning-2' : undefined}
|
||||
ref={ref}
|
||||
role='group'
|
||||
display='flex'
|
||||
flexDirection='column'
|
||||
overflow='hidden'
|
||||
padding={0}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export default MessageComposer;
|
||||
@@ -0,0 +1,6 @@
|
||||
import { IconButton } from '@rocket.chat/fuselage';
|
||||
import type { ComponentProps } from 'react';
|
||||
|
||||
const MessageComposerAction = (props: ComponentProps<typeof IconButton>) => <IconButton small {...props} />;
|
||||
|
||||
export default MessageComposerAction;
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Divider } from '@rocket.chat/fuselage';
|
||||
import type { ComponentProps } from 'react';
|
||||
|
||||
const MessageComposerActionsDivider = ({ height = 'x20', ...props }: ComponentProps<typeof Divider>) => (
|
||||
<Divider vertical marginInline={4} borderColor='light' marginBlock={0} backgroundColor='selected' height={height} {...props} />
|
||||
);
|
||||
|
||||
export default MessageComposerActionsDivider;
|
||||
@@ -0,0 +1,6 @@
|
||||
import { Button } from '@rocket.chat/fuselage';
|
||||
import type { ComponentProps } from 'react';
|
||||
|
||||
const MessageComposerButton = (props: ComponentProps<typeof Button>) => <Button small {...props} />;
|
||||
|
||||
export default MessageComposerButton;
|
||||
@@ -0,0 +1,111 @@
|
||||
import { css } from '@rocket.chat/css-in-js';
|
||||
import { Avatar, Box, Palette, Skeleton } from '@rocket.chat/fuselage';
|
||||
import { useButtonPattern } from '@rocket.chat/fuselage-hooks';
|
||||
import { FilePreviewIcon } from '@rocket.chat/ui-client';
|
||||
import type { ReactNode, KeyboardEvent, MouseEvent, AllHTMLAttributes } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export type MessageComposerFileProps = {
|
||||
fileTitle: string;
|
||||
fileSubtitle: string;
|
||||
fileFormat: string;
|
||||
showPreview?: boolean;
|
||||
previewUrl?: string;
|
||||
alt?: string;
|
||||
actionIcon: ReactNode;
|
||||
error?: boolean;
|
||||
disabled?: boolean;
|
||||
onClick: () => void;
|
||||
} & Omit<AllHTMLAttributes<HTMLButtonElement>, 'is'>;
|
||||
|
||||
const MessageComposerFile = ({
|
||||
fileTitle,
|
||||
fileSubtitle,
|
||||
fileFormat,
|
||||
showPreview,
|
||||
previewUrl,
|
||||
alt = '',
|
||||
actionIcon,
|
||||
error,
|
||||
disabled,
|
||||
onClick,
|
||||
className,
|
||||
...props
|
||||
}: MessageComposerFileProps) => {
|
||||
const previewWrapperStyle = css`
|
||||
background-color: ${Palette.surface['surface-tint']};
|
||||
cursor: ${error || disabled ? 'not-allowed' : 'pointer'};
|
||||
|
||||
&:hover {
|
||||
background-color: ${!error && !disabled ? Palette.surface['surface-hover'] : Palette.surface['surface-tint']};
|
||||
}
|
||||
`;
|
||||
|
||||
const handleClick = (e: MouseEvent<Element> | KeyboardEvent<Element>) => {
|
||||
e.stopPropagation();
|
||||
if (!error && !disabled) {
|
||||
onClick();
|
||||
}
|
||||
};
|
||||
|
||||
const buttonProps = useButtonPattern(handleClick);
|
||||
|
||||
const subtitleColor = useMemo(() => {
|
||||
if (error) {
|
||||
return 'danger';
|
||||
}
|
||||
|
||||
if (disabled) {
|
||||
return 'disabled';
|
||||
}
|
||||
|
||||
return 'hint';
|
||||
}, [disabled, error]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
rcx-input-box__wrapper={!error && !disabled}
|
||||
readOnly={error}
|
||||
className={[previewWrapperStyle, className].filter(Boolean)}
|
||||
role='group'
|
||||
aria-label={fileTitle}
|
||||
display='flex'
|
||||
flexShrink={0}
|
||||
flexGrow={0}
|
||||
padding={4}
|
||||
borderRadius={4}
|
||||
borderWidth={1}
|
||||
borderColor={error ? 'error' : 'extra-light'}
|
||||
alignItems='center'
|
||||
position='relative'
|
||||
height='x58'
|
||||
width='x234'
|
||||
marginInlineEnd={8}
|
||||
onClick={handleClick}
|
||||
{...props}
|
||||
>
|
||||
{showPreview ? (
|
||||
<Box minWidth='x48'>
|
||||
{previewUrl ? (
|
||||
<Avatar objectFit='cover' url={previewUrl} size='x48' alt={alt} />
|
||||
) : (
|
||||
<Skeleton variant='rect' width='x48' height='x48' />
|
||||
)}
|
||||
</Box>
|
||||
) : (
|
||||
<FilePreviewIcon format={fileFormat} />
|
||||
)}
|
||||
<Box flexGrow={1} withTruncatedText marginInlineStart={4} display='flex' flexDirection='column'>
|
||||
<Box {...buttonProps} fontScale='p2' color={disabled ? 'disabled' : 'info'} withTruncatedText>
|
||||
{fileTitle}
|
||||
</Box>
|
||||
<Box fontScale='c1' color={subtitleColor} textTransform={!error ? 'uppercase' : 'none'} withTruncatedText>
|
||||
{fileSubtitle}
|
||||
</Box>
|
||||
</Box>
|
||||
{!disabled && <Box alignSelf='start'>{actionIcon}</Box>}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default MessageComposerFile;
|
||||
@@ -0,0 +1,30 @@
|
||||
import type { AllHTMLAttributes, ReactNode } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import MessageComposerFile from './MessageComposerFile';
|
||||
|
||||
export type MessageComposerFileErrorProps = {
|
||||
fileTitle: string;
|
||||
fileFormat: string;
|
||||
error: Error;
|
||||
actionIcon: ReactNode;
|
||||
onClick: () => void;
|
||||
} & AllHTMLAttributes<HTMLButtonElement>;
|
||||
|
||||
const MessageComposerFileError = ({ fileTitle, error, actionIcon, onClick, ...props }: MessageComposerFileErrorProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<MessageComposerFile
|
||||
error={true}
|
||||
fileTitle={fileTitle}
|
||||
fileSubtitle={t('Upload_failed')}
|
||||
actionIcon={actionIcon}
|
||||
title={error.message}
|
||||
onClick={onClick}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default MessageComposerFileError;
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Box } from '@rocket.chat/fuselage';
|
||||
import type { ComponentProps } from 'react';
|
||||
|
||||
const MessageComposerFileGroup = ({ children, style, ...props }: ComponentProps<typeof Box>) => {
|
||||
return (
|
||||
<Box
|
||||
role='group'
|
||||
display='flex'
|
||||
width='100%'
|
||||
flexDirection='row'
|
||||
paddingInline={8}
|
||||
paddingBlockEnd={8}
|
||||
paddingBlockStart={2}
|
||||
overflowX='auto'
|
||||
style={{ whiteSpace: 'nowrap', ...style }}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default MessageComposerFileGroup;
|
||||
@@ -0,0 +1,41 @@
|
||||
import { css } from '@rocket.chat/css-in-js';
|
||||
import { Box, Palette } from '@rocket.chat/fuselage';
|
||||
import type { AllHTMLAttributes } from 'react';
|
||||
|
||||
const MessageComposerFileLoader = ({ className, ...props }: Omit<AllHTMLAttributes<HTMLOrSVGElement>, 'is'>) => {
|
||||
const customCSS = css`
|
||||
animation: spin-animation 0.8s linear infinite;
|
||||
|
||||
@keyframes spin-animation {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
return (
|
||||
<Box
|
||||
className={[customCSS, className].filter(Boolean)}
|
||||
is='svg'
|
||||
size='x24'
|
||||
viewBox='0 0 24 24'
|
||||
fill='none'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
{...props}
|
||||
>
|
||||
<circle cx='11.9998' cy='12' r='8' stroke={Palette.stroke['stroke-extra-light'].toString()} strokeWidth='2' />
|
||||
<path
|
||||
d='M20 12C20 16.4183 16.4183 20 12 20C7.58172 20 4 16.4183 4 12'
|
||||
stroke={Palette.stroke['stroke-highlight'].toString()}
|
||||
strokeWidth='2'
|
||||
strokeLinecap='round'
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default MessageComposerFileLoader;
|
||||
@@ -0,0 +1,4 @@
|
||||
export { default as MessageComposerFile } from './MessageComposerFile';
|
||||
export { default as MessageComposerFileError } from './MessageComposerFileError';
|
||||
export { default as MessageComposerFileLoader } from './MessageComposerFileLoader';
|
||||
export { default as MessageComposerFileGroup } from './MessageComposerFileGroup';
|
||||
@@ -0,0 +1,19 @@
|
||||
import { composeStories } from '@storybook/react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { axe } from 'jest-axe';
|
||||
|
||||
import * as stories from './MessageComposerHint.stories';
|
||||
|
||||
const testCases = Object.values(composeStories(stories)).map((Story) => [Story.storyName || 'Story', Story]);
|
||||
|
||||
test.each(testCases)(`renders %s without crashing`, async (_storyname, Story) => {
|
||||
const { baseElement } = render(<Story />);
|
||||
expect(baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test.each(testCases)('%s should have no a11y violations', async (_storyname, Story) => {
|
||||
const { container } = render(<Story />);
|
||||
|
||||
const results = await axe(container);
|
||||
expect(results).toHaveNoViolations();
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { MessageComposerHint } from '.';
|
||||
|
||||
export default {
|
||||
component: MessageComposerHint,
|
||||
} as Meta<typeof MessageComposerHint>;
|
||||
|
||||
export const HintWithIconAndHelperText: StoryObj<typeof MessageComposerHint> = {
|
||||
render: () => {
|
||||
const helperText = (
|
||||
<>
|
||||
<strong>esc</strong> to cancel · <strong>enter</strong> to save
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<MessageComposerHint icon='pencil' helperText={helperText}>
|
||||
Editing message
|
||||
</MessageComposerHint>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const HintWithIcon: StoryObj<typeof MessageComposerHint> = {
|
||||
render: () => <MessageComposerHint icon='eye'>This room is read only</MessageComposerHint>,
|
||||
};
|
||||
|
||||
export const HintWithText: StoryObj<typeof MessageComposerHint> = {
|
||||
render: () => <MessageComposerHint>You're sending an unencrypted message</MessageComposerHint>,
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
import type { IconProps } from '@rocket.chat/fuselage';
|
||||
import { Box, Icon, Tag } from '@rocket.chat/fuselage';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
export type MessageComposerHintProps = {
|
||||
children: string;
|
||||
icon?: IconProps['name'];
|
||||
helperText?: ReactNode;
|
||||
};
|
||||
|
||||
const MessageComposerHint = ({ icon, children, helperText }: MessageComposerHintProps) => (
|
||||
<Box paddingBlockStart={0} paddingBlockEnd={4} display='flex' flexDirection='row' justifyContent='space-between' alignItems='center'>
|
||||
<Tag icon={icon ? <Icon marginInlineEnd={4} name={icon} size='x12' /> : undefined}>{children}</Tag>
|
||||
{helperText && (
|
||||
<Box fontScale='c1' color='hint'>
|
||||
{helperText}
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
export default MessageComposerHint;
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Icon } from '@rocket.chat/fuselage';
|
||||
import type { Keys } from '@rocket.chat/icons';
|
||||
import type { HTMLAttributes } from 'react';
|
||||
|
||||
export type MessageComposerIconProps = { name: Keys } & Omit<HTMLAttributes<HTMLElement>, 'is'>;
|
||||
|
||||
const MessageComposerIcon = ({ name, ...props }: MessageComposerIconProps) => (
|
||||
<Icon name={name} size='x20' marginInlineEnd={4} {...props} />
|
||||
);
|
||||
|
||||
export default MessageComposerIcon;
|
||||
@@ -0,0 +1,36 @@
|
||||
import { css } from '@rocket.chat/css-in-js';
|
||||
import { Box, Palette } from '@rocket.chat/fuselage';
|
||||
import type { ComponentProps } from 'react';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
const messageComposerInputStyle = css`
|
||||
resize: none;
|
||||
|
||||
&::placeholder {
|
||||
color: ${Palette.text['font-annotation']};
|
||||
}
|
||||
`;
|
||||
|
||||
export type MessageComposerInputProps = ComponentProps<typeof Box>;
|
||||
|
||||
const MessageComposerInput = forwardRef<HTMLTextAreaElement, MessageComposerInputProps>(function MessageComposerInput(props, ref) {
|
||||
return (
|
||||
<Box
|
||||
className={[messageComposerInputStyle, 'rc-message-box__textarea js-input-message']}
|
||||
color='default'
|
||||
width='full'
|
||||
minHeight={52}
|
||||
maxHeight={155}
|
||||
rows={1}
|
||||
fontScale='p2'
|
||||
ref={ref}
|
||||
paddingInline={12}
|
||||
paddingBlock={16}
|
||||
borderWidth={0}
|
||||
is='textarea'
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export default MessageComposerInput;
|
||||
@@ -0,0 +1,124 @@
|
||||
import { mockAppRoot } from '@rocket.chat/mock-providers';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import MessageComposerInputExpandable from './MessageComposerInputExpandable';
|
||||
|
||||
test('should show expand button when dimensions.blockSize > 100', () => {
|
||||
render(
|
||||
<MessageComposerInputExpandable
|
||||
dimensions={{
|
||||
inlineSize: 400,
|
||||
blockSize: 120,
|
||||
}}
|
||||
placeholder='Type a message...'
|
||||
/>,
|
||||
{ wrapper: mockAppRoot().build() },
|
||||
);
|
||||
|
||||
const expandButton = screen.getByRole('button');
|
||||
expect(expandButton).toBeInTheDocument();
|
||||
expect(expandButton).toHaveAttribute('title', 'Expand');
|
||||
});
|
||||
|
||||
test('should not show expand button when dimensions.blockSize <= 100', () => {
|
||||
render(
|
||||
<MessageComposerInputExpandable
|
||||
dimensions={{
|
||||
inlineSize: 400,
|
||||
blockSize: 80,
|
||||
}}
|
||||
placeholder='Type a message...'
|
||||
/>,
|
||||
{ wrapper: mockAppRoot().build() },
|
||||
);
|
||||
|
||||
const expandButton = screen.queryByRole('button');
|
||||
expect(expandButton).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('should expand input when expand button is clicked', async () => {
|
||||
render(
|
||||
<MessageComposerInputExpandable
|
||||
dimensions={{
|
||||
inlineSize: 400,
|
||||
blockSize: 120,
|
||||
}}
|
||||
placeholder='Type a message...'
|
||||
/>,
|
||||
{ wrapper: mockAppRoot().build() },
|
||||
);
|
||||
|
||||
const expandButton = screen.getByRole('button');
|
||||
const textarea = screen.getByRole('textbox');
|
||||
|
||||
// Initially not expanded
|
||||
expect(textarea).not.toHaveStyle({ height: '500px' });
|
||||
|
||||
// Click to expand
|
||||
await userEvent.click(expandButton);
|
||||
|
||||
// Should be expanded now
|
||||
expect(textarea).toHaveStyle({ height: '500px' });
|
||||
expect(textarea).toHaveStyle({ maxHeight: '50vh' });
|
||||
expect(expandButton).toHaveAttribute('title', 'Collapse');
|
||||
});
|
||||
|
||||
test('should collapse input when collapse button is clicked', async () => {
|
||||
render(
|
||||
<MessageComposerInputExpandable
|
||||
dimensions={{
|
||||
inlineSize: 400,
|
||||
blockSize: 120,
|
||||
}}
|
||||
placeholder='Type a message...'
|
||||
/>,
|
||||
{ wrapper: mockAppRoot().build() },
|
||||
);
|
||||
|
||||
const expandButton = screen.getByRole('button');
|
||||
const textarea = screen.getByRole('textbox');
|
||||
|
||||
// Expand first
|
||||
await userEvent.click(expandButton);
|
||||
expect(textarea).toHaveStyle({ height: '500px' });
|
||||
|
||||
// Click to collapse
|
||||
await userEvent.click(expandButton);
|
||||
|
||||
// Should be collapsed now
|
||||
expect(textarea).not.toHaveStyle({ height: '500px' });
|
||||
expect(textarea).not.toHaveStyle({ maxHeight: '50vh' });
|
||||
expect(expandButton).toHaveAttribute('title', 'Expand');
|
||||
});
|
||||
|
||||
test('should auto-collapse when input is cleared', async () => {
|
||||
render(
|
||||
<MessageComposerInputExpandable
|
||||
dimensions={{
|
||||
inlineSize: 400,
|
||||
blockSize: 120,
|
||||
}}
|
||||
placeholder='Type a message...'
|
||||
/>,
|
||||
{ wrapper: mockAppRoot().build() },
|
||||
);
|
||||
|
||||
const expandButton = screen.getByRole('button');
|
||||
const textarea = screen.getByRole('textbox');
|
||||
|
||||
// Expand first
|
||||
await userEvent.click(expandButton);
|
||||
expect(textarea).toHaveStyle({ height: '500px' });
|
||||
|
||||
// Type some text
|
||||
await userEvent.type(textarea, 'Some text');
|
||||
expect(textarea).toHaveStyle({ height: '500px' });
|
||||
|
||||
// Clear the text
|
||||
await userEvent.clear(textarea);
|
||||
|
||||
// Should auto-collapse
|
||||
expect(textarea).not.toHaveStyle({ height: '500px' });
|
||||
expect(textarea).not.toHaveStyle({ maxHeight: '50vh' });
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
import { css } from '@rocket.chat/css-in-js';
|
||||
import { Box, IconButton } from '@rocket.chat/fuselage';
|
||||
import { useState, forwardRef } from 'react';
|
||||
import type { ChangeEvent, ComponentProps } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import MessageComposerInput from './MessageComposerInput';
|
||||
|
||||
export type ExpandComposerButtonProps = ComponentProps<typeof Box> & {
|
||||
dimensions: Readonly<{
|
||||
inlineSize: number;
|
||||
blockSize: number;
|
||||
}>;
|
||||
};
|
||||
|
||||
const MessageComposerInputExpandable = forwardRef<HTMLTextAreaElement, ExpandComposerButtonProps>(
|
||||
({ dimensions, onChange, ...props }, ref) => {
|
||||
const { t } = useTranslation();
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
|
||||
const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
if (event.target.value.length === 0) {
|
||||
setExpanded(false);
|
||||
}
|
||||
|
||||
onChange?.(event);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{dimensions.blockSize > 100 && (
|
||||
<Box
|
||||
position='absolute'
|
||||
padding={8}
|
||||
className={css`
|
||||
top: 0;
|
||||
right: 0;
|
||||
`}
|
||||
>
|
||||
<IconButton
|
||||
small
|
||||
icon={expanded ? 'arrow-collapse' : 'arrow-expand'}
|
||||
title={expanded ? t('Collapse') : t('Expand')}
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
<MessageComposerInput ref={ref} onChange={handleChange} {...(!!expanded && { height: 500, maxHeight: '50vh' })} {...props} />
|
||||
</>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
MessageComposerInputExpandable.displayName = 'MessageComposerInputExpandable';
|
||||
|
||||
export default MessageComposerInputExpandable;
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Skeleton, Box } from '@rocket.chat/fuselage';
|
||||
|
||||
import { MessageComposer, MessageComposerToolbar } from '.';
|
||||
|
||||
const MessageComposerSkeleton = () => (
|
||||
<MessageComposer>
|
||||
<Box width='100%' display='flex' alignItems='center' height='x52' paddingInline={12}>
|
||||
<Skeleton width='100%' height={36} />
|
||||
</Box>
|
||||
<MessageComposerToolbar height={36} />
|
||||
</MessageComposer>
|
||||
);
|
||||
|
||||
export default MessageComposerSkeleton;
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Box } from '@rocket.chat/fuselage';
|
||||
import type { ComponentProps } from 'react';
|
||||
|
||||
const MessageComposerToolbar = (props: ComponentProps<typeof Box>) => (
|
||||
<Box backgroundColor='surface-neutral' padding={4} display='flex' justifyContent='space-between' width='full' {...props} />
|
||||
);
|
||||
|
||||
export default MessageComposerToolbar;
|
||||
@@ -0,0 +1,16 @@
|
||||
import { useToolbar } from '@react-aria/toolbar';
|
||||
import { ButtonGroup } from '@rocket.chat/fuselage';
|
||||
import { useRef, type ComponentProps } from 'react';
|
||||
|
||||
const MessageComposerToolbarActions = (props: ComponentProps<typeof ButtonGroup>) => {
|
||||
const ref = useRef(null);
|
||||
const { toolbarProps } = useToolbar(props, ref);
|
||||
|
||||
return (
|
||||
<ButtonGroup role='toolbar' small ref={ref} {...toolbarProps}>
|
||||
{props.children}
|
||||
</ButtonGroup>
|
||||
);
|
||||
};
|
||||
|
||||
export default MessageComposerToolbarActions;
|
||||
@@ -0,0 +1,6 @@
|
||||
import { ButtonGroup } from '@rocket.chat/fuselage';
|
||||
import type { ComponentProps } from 'react';
|
||||
|
||||
const MessageComposerToolbarSubmit = (props: ComponentProps<typeof ButtonGroup>) => <ButtonGroup small {...props} />;
|
||||
|
||||
export default MessageComposerToolbarSubmit;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,85 @@
|
||||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||
|
||||
exports[`renders HintWithIcon without crashing 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="rcx-box rcx-box--full rcx-css-r3aouy"
|
||||
>
|
||||
<span
|
||||
class="rcx-box rcx-box--full rcx-tag "
|
||||
>
|
||||
<i
|
||||
aria-hidden="true"
|
||||
class="rcx-box rcx-box--full rcx-icon--name-eye rcx-icon rcx-css-nbjs1j"
|
||||
>
|
||||
|
||||
</i>
|
||||
<span
|
||||
class="rcx-tag__inner"
|
||||
>
|
||||
This room is read only
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`renders HintWithIconAndHelperText without crashing 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="rcx-box rcx-box--full rcx-css-r3aouy"
|
||||
>
|
||||
<span
|
||||
class="rcx-box rcx-box--full rcx-tag "
|
||||
>
|
||||
<i
|
||||
aria-hidden="true"
|
||||
class="rcx-box rcx-box--full rcx-icon--name-pencil rcx-icon rcx-css-nbjs1j"
|
||||
>
|
||||
⦏
|
||||
</i>
|
||||
<span
|
||||
class="rcx-tag__inner"
|
||||
>
|
||||
Editing message
|
||||
</span>
|
||||
</span>
|
||||
<div
|
||||
class="rcx-box rcx-box--full rcx-css-1dp5kdc"
|
||||
>
|
||||
<strong>
|
||||
esc
|
||||
</strong>
|
||||
to cancel ·
|
||||
<strong>
|
||||
enter
|
||||
</strong>
|
||||
to save
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`renders HintWithText without crashing 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="rcx-box rcx-box--full rcx-css-r3aouy"
|
||||
>
|
||||
<span
|
||||
class="rcx-box rcx-box--full rcx-tag "
|
||||
>
|
||||
<span
|
||||
class="rcx-tag__inner"
|
||||
>
|
||||
You're sending an unencrypted message
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
29
packages/ui-composer/src/MessageComposer/index.ts
Normal file
29
packages/ui-composer/src/MessageComposer/index.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import MessageComposer from './MessageComposer';
|
||||
import MessageComposerAction from './MessageComposerAction';
|
||||
import MessageComposerActionsDivider from './MessageComposerActionsDivider';
|
||||
import MessageComposerButton from './MessageComposerButton';
|
||||
import MessageComposerHint from './MessageComposerHint';
|
||||
import MessageComposerIcon from './MessageComposerIcon';
|
||||
import MessageComposerInput from './MessageComposerInput';
|
||||
import MessageComposerInputExpandable from './MessageComposerInputExpandable';
|
||||
import MessageComposerSkeleton from './MessageComposerSkeleton';
|
||||
import MessageComposerToolbar from './MessageComposerToolbar';
|
||||
import MessageComposerToolbarActions from './MessageComposerToolbarActions';
|
||||
import MessageComposerToolbarSubmit from './MessageComposerToolbarSubmit';
|
||||
|
||||
export {
|
||||
MessageComposer,
|
||||
MessageComposerAction,
|
||||
MessageComposerActionsDivider,
|
||||
MessageComposerInput,
|
||||
MessageComposerInputExpandable,
|
||||
MessageComposerToolbar,
|
||||
MessageComposerToolbarActions,
|
||||
MessageComposerToolbarSubmit,
|
||||
MessageComposerSkeleton,
|
||||
MessageComposerIcon,
|
||||
MessageComposerHint,
|
||||
MessageComposerButton,
|
||||
};
|
||||
|
||||
export { MessageComposerFile, MessageComposerFileError, MessageComposerFileLoader, MessageComposerFileGroup } from './MessageComposerFile';
|
||||
@@ -0,0 +1,19 @@
|
||||
import { composeStories } from '@storybook/react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { axe } from 'jest-axe';
|
||||
|
||||
import * as stories from './MessageFooterCallout.stories';
|
||||
|
||||
const testCases = Object.values(composeStories(stories)).map((Story) => [Story.storyName || 'Story', Story]);
|
||||
|
||||
test.each(testCases)(`renders %s without crashing`, async (_storyname, Story) => {
|
||||
const { baseElement } = render(<Story />);
|
||||
expect(baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test.each(testCases)('%s should have no a11y violations', async (_storyname, Story) => {
|
||||
const { container } = render(<Story />);
|
||||
|
||||
const results = await axe(container);
|
||||
expect(results).toHaveNoViolations();
|
||||
});
|
||||
@@ -0,0 +1,59 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { MessageFooterCallout, MessageFooterCalloutAction } from '.';
|
||||
import MessageFooterCalloutContent from './MessageFooterCalloutContent';
|
||||
import MessageFooterCalloutDivider from './MessageFooterCalloutDivider';
|
||||
import MessageComposer from '../MessageComposer/MessageComposer';
|
||||
import MessageComposerIcon from '../MessageComposer/MessageComposerIcon';
|
||||
|
||||
export default {
|
||||
component: MessageComposer,
|
||||
} satisfies Meta<typeof MessageComposer>;
|
||||
|
||||
export const MessageComposerBlocked: StoryObj<typeof MessageComposer> = {
|
||||
render: () => (
|
||||
<MessageFooterCallout>
|
||||
<MessageComposerIcon name='burger' />
|
||||
Feedback text
|
||||
</MessageFooterCallout>
|
||||
),
|
||||
};
|
||||
|
||||
export const MessageComposerBlockedLargeText: StoryObj<typeof MessageComposer> = {
|
||||
render: () => (
|
||||
<MessageFooterCallout>
|
||||
<MessageComposerIcon name='burger' />
|
||||
<MessageFooterCalloutContent>
|
||||
Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text
|
||||
Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text text Feedback text Feedback text Feedback text
|
||||
Feedback text Feedback text text Feedback text Feedback text Feedback text Feedback text Feedback text text Feedback text Feedback
|
||||
text Feedback text Feedback text Feedback text
|
||||
</MessageFooterCalloutContent>
|
||||
<MessageFooterCalloutAction onClick={(): void => undefined}>Button</MessageFooterCalloutAction>
|
||||
</MessageFooterCallout>
|
||||
),
|
||||
};
|
||||
|
||||
export const MessageComposerBlockedLargeTextDashed: StoryObj<typeof MessageComposer> = {
|
||||
render: () => (
|
||||
<MessageFooterCallout dashed>
|
||||
<MessageComposerIcon name='burger' />
|
||||
<MessageFooterCalloutContent>
|
||||
Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text
|
||||
Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text text Feedback text Feedback text Feedback text
|
||||
Feedback text Feedback text text Feedback text Feedback text Feedback text Feedback text Feedback text text Feedback text Feedback
|
||||
text Feedback text Feedback text Feedback text
|
||||
</MessageFooterCalloutContent>
|
||||
<MessageFooterCalloutAction onClick={(): void => undefined}>Button</MessageFooterCalloutAction>
|
||||
</MessageFooterCallout>
|
||||
),
|
||||
};
|
||||
|
||||
export const _MessageFooterCalloutAction: StoryObj<typeof MessageComposer> = {
|
||||
render: () => (
|
||||
<MessageFooterCallout>
|
||||
Feedback text <MessageFooterCalloutDivider />
|
||||
<MessageFooterCalloutAction onClick={(): void => undefined}>Button</MessageFooterCalloutAction>
|
||||
</MessageFooterCallout>
|
||||
),
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Box } from '@rocket.chat/fuselage';
|
||||
import type { ElementType, HTMLAttributes, ReactNode } from 'react';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
const MessageFooterCallout = forwardRef<
|
||||
HTMLElement,
|
||||
Omit<HTMLAttributes<HTMLElement>, 'is'> & {
|
||||
children: ReactNode;
|
||||
is?: ElementType<any>;
|
||||
variant?: 'default' | 'error';
|
||||
dashed?: boolean;
|
||||
}
|
||||
>(function MessageFooterCallout({ dashed, ...props }, ref) {
|
||||
return (
|
||||
<Box
|
||||
ref={ref}
|
||||
{...(dashed && {
|
||||
borderStyle: 'dashed',
|
||||
})}
|
||||
display='flex'
|
||||
borderWidth={2}
|
||||
borderColor='light'
|
||||
borderRadius='x4'
|
||||
padding={8}
|
||||
marginBlockEnd={24}
|
||||
backgroundColor='surface-tint'
|
||||
alignItems='center'
|
||||
minHeight='x48'
|
||||
justifyContent='center'
|
||||
color='default'
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export default MessageFooterCallout;
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Button } from '@rocket.chat/fuselage';
|
||||
import type { ComponentProps } from 'react';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
export type MessageFooterCalloutActionProps = ComponentProps<typeof Button>;
|
||||
|
||||
const MessageFooterCalloutAction = forwardRef<HTMLButtonElement, MessageFooterCalloutActionProps>(
|
||||
function MessageFooterCalloutAction(props, ref) {
|
||||
return <Button marginInline={4} ref={ref} primary small flexShrink={0} {...props} />;
|
||||
},
|
||||
);
|
||||
|
||||
export default MessageFooterCalloutAction;
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Box } from '@rocket.chat/fuselage';
|
||||
import type { ComponentProps } from 'react';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
export type MessageFooterCalloutContentProps = ComponentProps<typeof Box>;
|
||||
|
||||
const MessageFooterCalloutContent = forwardRef<HTMLDivElement, MessageFooterCalloutContentProps>(
|
||||
function MessageFooterCalloutContent(props, ref) {
|
||||
return <Box marginInline={4} ref={ref} flexWrap='wrap' textAlign='center' color='default' flexGrow={1} flexShrink={1} {...props} />;
|
||||
},
|
||||
);
|
||||
|
||||
export default MessageFooterCalloutContent;
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Box } from '@rocket.chat/fuselage';
|
||||
import { forwardRef } from 'react';
|
||||
|
||||
const MessageFooterCalloutDivider = forwardRef<HTMLButtonElement>(function MessageFooterCalloutDivider(props, ref) {
|
||||
return <Box is='hr' ref={ref} borderInlineStart='1px solid' marginInline={4} flexShrink={0} {...props} />;
|
||||
});
|
||||
|
||||
export default MessageFooterCalloutDivider;
|
||||
@@ -0,0 +1,108 @@
|
||||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||
|
||||
exports[`renders _MessageFooterCalloutAction without crashing 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="rcx-box rcx-box--full rcx-css-l452z"
|
||||
>
|
||||
Feedback text
|
||||
<hr
|
||||
class="rcx-box rcx-box--full rcx-css-vi5s2c"
|
||||
/>
|
||||
<button
|
||||
class="rcx-box rcx-box--full rcx-button--small rcx-button--primary rcx-button rcx-css-1dy74d9"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="rcx-button--content"
|
||||
>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`renders MessageComposerBlocked without crashing 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="rcx-box rcx-box--full rcx-css-l452z"
|
||||
>
|
||||
<i
|
||||
aria-hidden="true"
|
||||
class="rcx-box rcx-box--full rcx-icon--name-burger rcx-icon rcx-css-1c32rho"
|
||||
>
|
||||
|
||||
</i>
|
||||
Feedback text
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`renders MessageComposerBlockedLargeText without crashing 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="rcx-box rcx-box--full rcx-css-l452z"
|
||||
>
|
||||
<i
|
||||
aria-hidden="true"
|
||||
class="rcx-box rcx-box--full rcx-icon--name-burger rcx-icon rcx-css-1c32rho"
|
||||
>
|
||||
|
||||
</i>
|
||||
<div
|
||||
class="rcx-box rcx-box--full rcx-css-vfwfo1"
|
||||
>
|
||||
Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text text Feedback text Feedback text Feedback text Feedback text Feedback text text Feedback text Feedback text Feedback text Feedback text Feedback text text Feedback text Feedback text Feedback text Feedback text Feedback text
|
||||
</div>
|
||||
<button
|
||||
class="rcx-box rcx-box--full rcx-button--small rcx-button--primary rcx-button rcx-css-1dy74d9"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="rcx-button--content"
|
||||
>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`renders MessageComposerBlockedLargeTextDashed without crashing 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="rcx-box rcx-box--full rcx-css-1pl9ovb"
|
||||
>
|
||||
<i
|
||||
aria-hidden="true"
|
||||
class="rcx-box rcx-box--full rcx-icon--name-burger rcx-icon rcx-css-1c32rho"
|
||||
>
|
||||
|
||||
</i>
|
||||
<div
|
||||
class="rcx-box rcx-box--full rcx-css-vfwfo1"
|
||||
>
|
||||
Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text Feedback text text Feedback text Feedback text Feedback text Feedback text Feedback text text Feedback text Feedback text Feedback text Feedback text Feedback text text Feedback text Feedback text Feedback text Feedback text Feedback text
|
||||
</div>
|
||||
<button
|
||||
class="rcx-box rcx-box--full rcx-button--small rcx-button--primary rcx-button rcx-css-1dy74d9"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="rcx-button--content"
|
||||
>
|
||||
Button
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
6
packages/ui-composer/src/MessageFooterCallout/index.ts
Normal file
6
packages/ui-composer/src/MessageFooterCallout/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import MessageFooterCallout from './MessageFooterCallout';
|
||||
import MessageFooterCalloutAction from './MessageFooterCalloutAction';
|
||||
import MessageFooterCalloutContent from './MessageFooterCalloutContent';
|
||||
import MessageFooterCalloutDivider from './MessageFooterCalloutDivider';
|
||||
|
||||
export { MessageFooterCallout, MessageFooterCalloutAction, MessageFooterCalloutDivider, MessageFooterCalloutContent };
|
||||
2
packages/ui-composer/src/index.ts
Normal file
2
packages/ui-composer/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './MessageComposer';
|
||||
export * from './MessageFooterCallout';
|
||||
4
packages/ui-composer/tsconfig.build.json
Normal file
4
packages/ui-composer/tsconfig.build.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["**/*.stories.tsx", "./src/**/*.spec.ts", "./src/**/*.spec.tsx", "./.storybook/**/*", "./jest.config.ts"]
|
||||
}
|
||||
8
packages/ui-composer/tsconfig.json
Normal file
8
packages/ui-composer/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "@rocket.chat/tsconfig/client.json",
|
||||
"compilerOptions": {
|
||||
"rootDirs": ["./src", "./"],
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": ["./src/**/*", "./.storybook/**/*", "./jest.config.ts"],
|
||||
}
|
||||
Reference in New Issue
Block a user