@clubmed/usg-chat-ui 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/README.md +68 -0
- package/package.json +108 -0
- package/styles/index.css +171 -0
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<div style="text-align: center" align="center">
|
|
2
|
+
<img src="https://ns.clubmed.com/fbs/RWD/branding2023/Logo/MicrosoftTeams-image%20(9).png" width="200" alt="Club Med"/>
|
|
3
|
+
</div>
|
|
4
|
+
|
|
5
|
+
<div align="center">
|
|
6
|
+
<h1>@clubmed/usg-chat-ui</h1>
|
|
7
|
+
<hr />
|
|
8
|
+
|
|
9
|
+
[](https://badge.fury.io/js/%40clubmed%2Fusg-chat-ui)
|
|
10
|
+
[](https://github.com/semantic-release/semantic-release)
|
|
11
|
+
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
Reusable chat experience extracted from the ClubMed USG project. Everything is published as ESM-only output so it can be consumed by any Vite/Next/CRA-style React host.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @clubmed/usg-chat-ui
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Provider setup
|
|
23
|
+
|
|
24
|
+
Drop the ready-made `<Chat />` organism into your page and pass the minimal props (`apiUrl`, `accessToken`, `user`, optional `logout`). Internally it wires the chat provider, HTTP client, and feature contexts so you don’t need to juggle multiple wrappers.
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
import type {ChatUser} from "@clubmed/usg-chat-ui";
|
|
28
|
+
import {Chat} from "@clubmed/usg-chat-ui/organisms/Chat";;
|
|
29
|
+
|
|
30
|
+
const session = useSession(); // host-specific auth hook
|
|
31
|
+
|
|
32
|
+
export function ChatPanel() {
|
|
33
|
+
const user: ChatUser | null = session
|
|
34
|
+
? {
|
|
35
|
+
userId: session.userId,
|
|
36
|
+
userName: session.name,
|
|
37
|
+
userEmail: session.email,
|
|
38
|
+
}
|
|
39
|
+
: null;
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<ChatProvider>
|
|
43
|
+
apiUrl={process.env.API_URL!}
|
|
44
|
+
accessToken={session.accessToken}
|
|
45
|
+
user={user}
|
|
46
|
+
logout={session.logout}
|
|
47
|
+
>
|
|
48
|
+
<Chat />
|
|
49
|
+
</ChatProvider>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Configuration keys
|
|
55
|
+
|
|
56
|
+
| Field | Description |
|
|
57
|
+
|----------------------|-----------------------------------------------------------------------------------------|
|
|
58
|
+
| `config.apiUrl` | Base URL for server-to-server requests (e.g. `https://backend.internal`). |
|
|
59
|
+
| `config.fetcher` | Optional custom `fetch` implementation (for SSR polyfills, logging, etc.). |
|
|
60
|
+
| `config.accessToken` | Latest access token. When omitted/`null`, requests are sent anonymously. |
|
|
61
|
+
| `config.user` | Lightweight `{ userId, userName, userEmail }` object propagated via headers. |
|
|
62
|
+
| `logout` | Optional handler wired into settings so users can disconnect directly from the chat UI. |
|
|
63
|
+
|
|
64
|
+
If you need to customize HTTP transport or headers, provide a `fetcher` override or extend the HTTP client directly—`ChatProvider` keeps the config surface minimal (`apiUrl`, `fetcher`, `accessToken`, `user`).
|
|
65
|
+
|
|
66
|
+
## Storybook
|
|
67
|
+
|
|
68
|
+
Storybook v10 is configured at the workspace root (`usg-ui/.storybook`). Run `yarn storybook` from `usg-ui/` to browse molecules and verify appearance tokens in isolation. The build output (`storybook-static`) can be published alongside the npm package for visual regression if desired.
|
package/package.json
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@clubmed/usg-chat-ui",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Reusable ClubMed USG chat experience",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"module": "./index.js",
|
|
8
|
+
"types": "./index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./index.js",
|
|
12
|
+
"types": "./index.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./styles.css": "./styles/index.css",
|
|
15
|
+
"./core/*": {
|
|
16
|
+
"types": "./core/*.d.ts",
|
|
17
|
+
"import": "./core/*.js",
|
|
18
|
+
"default": "./core/*.js"
|
|
19
|
+
},
|
|
20
|
+
"./contexts/*": {
|
|
21
|
+
"types": "./contexts/*.d.ts",
|
|
22
|
+
"import": "./contexts/*.js",
|
|
23
|
+
"default": "./contexts/*.js"
|
|
24
|
+
},
|
|
25
|
+
"./molecules/*": {
|
|
26
|
+
"types": "./molecules/*.d.ts",
|
|
27
|
+
"import": "./molecules/*.js",
|
|
28
|
+
"default": "./molecules/*.js"
|
|
29
|
+
},
|
|
30
|
+
"./organisms/*": {
|
|
31
|
+
"types": "./organisms/*.d.ts",
|
|
32
|
+
"import": "./organisms/*.js",
|
|
33
|
+
"default": "./organisms/*.js"
|
|
34
|
+
},
|
|
35
|
+
"./utils/*": {
|
|
36
|
+
"types": "./utils/*.d.ts",
|
|
37
|
+
"import": "./utils/*.js",
|
|
38
|
+
"default": "./utils/*.js"
|
|
39
|
+
},
|
|
40
|
+
"./helpers/*": {
|
|
41
|
+
"types": "./utils/*.d.ts",
|
|
42
|
+
"import": "./utils/*.js",
|
|
43
|
+
"default": "./utils/*.js"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"files": [
|
|
47
|
+
"dist",
|
|
48
|
+
"styles",
|
|
49
|
+
"README.md",
|
|
50
|
+
"CHANGELOG.md"
|
|
51
|
+
],
|
|
52
|
+
"sideEffects": [
|
|
53
|
+
"./styles/index.css",
|
|
54
|
+
"./dist/assets/style.css"
|
|
55
|
+
],
|
|
56
|
+
"scripts": {
|
|
57
|
+
"clean": "rimraf dist",
|
|
58
|
+
"typecheck": "tsc --project tsconfig.json --noEmit",
|
|
59
|
+
"build": "npm run clean && vite build",
|
|
60
|
+
"test": "vitest run",
|
|
61
|
+
"test:watch": "vitest watch",
|
|
62
|
+
"dev": "vite build --watch"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"react": "^19.0.0",
|
|
66
|
+
"react-dom": "^19.0.0"
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@blocknote/core": "^0.41.1",
|
|
70
|
+
"@blocknote/mantine": "^0.41.1",
|
|
71
|
+
"@blocknote/react": "^0.41.1",
|
|
72
|
+
"@blocknote/xl-ai": "^0.41.1",
|
|
73
|
+
"@radix-ui/react-collapsible": "^1.1.12",
|
|
74
|
+
"@radix-ui/react-label": "^2.1.7",
|
|
75
|
+
"@radix-ui/react-slot": "^1.2.3",
|
|
76
|
+
"@radix-ui/react-tabs": "^1.1.13",
|
|
77
|
+
"@types/hast": "^3.0.4",
|
|
78
|
+
"@types/node": "^20.0.0",
|
|
79
|
+
"@types/react": "^19.0.0",
|
|
80
|
+
"@types/react-dom": "^19.0.0",
|
|
81
|
+
"@vitejs/plugin-react-swc": "^3.7.0",
|
|
82
|
+
"@y-sweet/client": "^0.9.1",
|
|
83
|
+
"ai": "^5.0.82",
|
|
84
|
+
"class-variance-authority": "^0.7.1",
|
|
85
|
+
"clsx": "^2.1.1",
|
|
86
|
+
"framer-motion": "^12.23.24",
|
|
87
|
+
"globby": "^13.2.2",
|
|
88
|
+
"isomorphic-dompurify": "^2.35.0",
|
|
89
|
+
"lucide-react": "^0.545.0",
|
|
90
|
+
"react": "^19.2.3",
|
|
91
|
+
"react-dom": "^19.2.3",
|
|
92
|
+
"react-markdown": "^10.1.0",
|
|
93
|
+
"remark-gfm": "^4.0.1",
|
|
94
|
+
"rimraf": "^5.0.5",
|
|
95
|
+
"rollup-preserve-directives": "^1.1.0",
|
|
96
|
+
"shiki": "^3.20.0",
|
|
97
|
+
"sonner": "^2.0.7",
|
|
98
|
+
"tailwind-merge": "^3.3.1",
|
|
99
|
+
"typescript": "^5.6.2",
|
|
100
|
+
"use-stick-to-bottom": "^1.1.1",
|
|
101
|
+
"vite": "^5.3.4",
|
|
102
|
+
"vite-plugin-dts": "4.5.4",
|
|
103
|
+
"vite-plugin-static-copy": "3.1.4",
|
|
104
|
+
"vite-plugin-svgr": "^4.2.0",
|
|
105
|
+
"yjs": "^13.6.27",
|
|
106
|
+
"zustand": "^5.0.8"
|
|
107
|
+
}
|
|
108
|
+
}
|
package/styles/index.css
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/* Placeholder styles for the @clubmed/usg-chat-ui package */
|
|
2
|
+
|
|
3
|
+
@tailwind base;
|
|
4
|
+
@tailwind components;
|
|
5
|
+
@tailwind utilities;
|
|
6
|
+
|
|
7
|
+
.usg-chat-ui {
|
|
8
|
+
--usg-chat-font: 'Inter', system-ui;
|
|
9
|
+
color-scheme: light;
|
|
10
|
+
--background: #ffffff;
|
|
11
|
+
--foreground: #111111;
|
|
12
|
+
--muted: #f4f4f5;
|
|
13
|
+
--muted-foreground: #3f3f46;
|
|
14
|
+
--border: #dcdcdc;
|
|
15
|
+
--card: #ffffff;
|
|
16
|
+
--card-foreground: #111111;
|
|
17
|
+
--accent: #e5e5e5;
|
|
18
|
+
--primary: #111111;
|
|
19
|
+
--primary-foreground: #f5f5f5;
|
|
20
|
+
--secondary: #f5f5f5;
|
|
21
|
+
--secondary-foreground: #1a1a1a;
|
|
22
|
+
--status-positive: #f2f2f2;
|
|
23
|
+
--status-positive-foreground: #161616;
|
|
24
|
+
--status-warning: #ededed;
|
|
25
|
+
--status-warning-foreground: #161616;
|
|
26
|
+
--status-critical: #e8e8e8;
|
|
27
|
+
--status-critical-foreground: #111111;
|
|
28
|
+
|
|
29
|
+
/* Spacing scale */
|
|
30
|
+
--spacing-xs: 0.25rem; /* 4px */
|
|
31
|
+
--spacing-sm: 0.5rem; /* 8px */
|
|
32
|
+
--spacing-md: 1rem; /* 16px */
|
|
33
|
+
--spacing-lg: 1.5rem; /* 24px */
|
|
34
|
+
--spacing-xl: 2rem; /* 32px */
|
|
35
|
+
--spacing-2xl: 3rem; /* 48px */
|
|
36
|
+
|
|
37
|
+
/* Shadows */
|
|
38
|
+
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
39
|
+
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
40
|
+
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
41
|
+
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
|
42
|
+
|
|
43
|
+
/* Radii */
|
|
44
|
+
--radius-sm: 0.5rem; /* 8px */
|
|
45
|
+
--radius-md: 0.75rem; /* 12px */
|
|
46
|
+
--radius-lg: 1rem; /* 16px */
|
|
47
|
+
--radius-xl: 1.5rem; /* 24px */
|
|
48
|
+
|
|
49
|
+
/* Blur */
|
|
50
|
+
--blur-sm: 4px;
|
|
51
|
+
--blur-md: 8px;
|
|
52
|
+
--blur-lg: 16px;
|
|
53
|
+
--blur-xl: 24px;
|
|
54
|
+
|
|
55
|
+
/* Transitions */
|
|
56
|
+
--transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
57
|
+
--transition-base: 250ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
58
|
+
--transition-slow: 350ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.usg-chat-ui.dark {
|
|
62
|
+
color-scheme: dark;
|
|
63
|
+
--background: #0b0b0b;
|
|
64
|
+
--foreground: #f5f5f5;
|
|
65
|
+
--muted: #1a1a1a;
|
|
66
|
+
--muted-foreground: #d4d4d8;
|
|
67
|
+
--border: #2a2a2a;
|
|
68
|
+
--card: #0f0f0f;
|
|
69
|
+
--card-foreground: #f5f5f5;
|
|
70
|
+
--accent: #1f1f1f;
|
|
71
|
+
--primary: #f5f5f5;
|
|
72
|
+
--primary-foreground: #111111;
|
|
73
|
+
--secondary: #161616;
|
|
74
|
+
--secondary-foreground: #f5f5f5;
|
|
75
|
+
--status-positive: #202020;
|
|
76
|
+
--status-positive-foreground: #f5f5f5;
|
|
77
|
+
--status-warning: #1c1c1c;
|
|
78
|
+
--status-warning-foreground: #f1f1f1;
|
|
79
|
+
--status-critical: #181818;
|
|
80
|
+
--status-critical-foreground: #f1f1f1;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.usg-chat-ui.light {
|
|
84
|
+
color-scheme: light;
|
|
85
|
+
--background: #ffffff;
|
|
86
|
+
--foreground: #111111;
|
|
87
|
+
--muted: #f4f4f5;
|
|
88
|
+
--muted-foreground: #3f3f46;
|
|
89
|
+
--border: #dcdcdc;
|
|
90
|
+
--card: #ffffff;
|
|
91
|
+
--card-foreground: #111111;
|
|
92
|
+
--accent: #e5e5e5;
|
|
93
|
+
--primary: #111111;
|
|
94
|
+
--primary-foreground: #f5f5f5;
|
|
95
|
+
--secondary: #f5f5f5;
|
|
96
|
+
--secondary-foreground: #1a1a1a;
|
|
97
|
+
--status-positive: #f2f2f2;
|
|
98
|
+
--status-positive-foreground: #161616;
|
|
99
|
+
--status-warning: #ededed;
|
|
100
|
+
--status-warning-foreground: #161616;
|
|
101
|
+
--status-critical: #e8e8e8;
|
|
102
|
+
--status-critical-foreground: #111111;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.usg-chat-ui {
|
|
106
|
+
background: var(--background);
|
|
107
|
+
color: var(--foreground);
|
|
108
|
+
font-family: var(--font-geist-sans), system-ui, sans-serif;
|
|
109
|
+
transition: background var(--transition-base), color var(--transition-base);
|
|
110
|
+
-webkit-font-smoothing: antialiased;
|
|
111
|
+
-moz-osx-font-smoothing: grayscale;
|
|
112
|
+
font-feature-settings: "rlig" 1, "calt" 1;
|
|
113
|
+
text-rendering: optimizeLegibility;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.usg-chat-ui code,
|
|
117
|
+
.usg-chat-ui pre,
|
|
118
|
+
.usg-chat-ui [class*="font-mono"],
|
|
119
|
+
.usg-chat-ui kbd {
|
|
120
|
+
font-family: var(--font-geist-mono), monospace;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* Ensure prose elements use Geist */
|
|
124
|
+
.usg-chat-ui .prose {
|
|
125
|
+
font-family: var(--font-geist-sans);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.usg-chat-ui .prose code {
|
|
129
|
+
font-family: var(--font-geist-mono);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.usg-chat-ui input,
|
|
133
|
+
.usg-chat-ui textarea,
|
|
134
|
+
.usg-chat-ui select {
|
|
135
|
+
color: inherit;
|
|
136
|
+
background-color: var(--background);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.usg-chat-ui input::placeholder,
|
|
140
|
+
.usg-chat-ui textarea::placeholder {
|
|
141
|
+
color: var(--muted-foreground);
|
|
142
|
+
opacity: 0.6;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Custom Scrollbar */
|
|
146
|
+
.usg-chat-ui ::-webkit-scrollbar {
|
|
147
|
+
width: 8px;
|
|
148
|
+
height: 8px;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.usg-chat-ui ::-webkit-scrollbar-track {
|
|
152
|
+
background: transparent;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.usg-chat-ui ::-webkit-scrollbar-thumb {
|
|
156
|
+
background: rgb(160 160 160 / 0.4);
|
|
157
|
+
border-radius: 4px;
|
|
158
|
+
transition: background var(--transition-fast);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.usg-chat-ui ::-webkit-scrollbar-thumb:hover {
|
|
162
|
+
background: rgb(160 160 160 / 0.6);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.usg-chat-ui.dark ::-webkit-scrollbar-thumb {
|
|
166
|
+
background: rgb(96 96 96 / 0.4);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.usg-chat-ui.dark ::-webkit-scrollbar-thumb:hover {
|
|
170
|
+
background: rgb(96 96 96 / 0.6);
|
|
171
|
+
}
|