@stromcom/react-snippet 0.1.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/LICENSE +21 -0
- package/README.md +247 -0
- package/dist/index.cjs +222 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.js +191 -0
- package/dist/index.js.map +1 -0
- package/package.json +72 -0
- package/src/StromcomConf.jsx +95 -0
- package/src/StromcomHome.jsx +26 -0
- package/src/StromcomProvider.jsx +105 -0
- package/src/StromcomThread.jsx +45 -0
- package/src/StromcomUser.jsx +41 -0
- package/src/__tests__/StromcomConf.test.jsx +52 -0
- package/src/__tests__/StromcomHome.test.jsx +57 -0
- package/src/__tests__/StromcomProvider.test.jsx +137 -0
- package/src/__tests__/StromcomThread.test.jsx +75 -0
- package/src/__tests__/StromcomUser.test.jsx +63 -0
- package/src/index.d.ts +85 -0
- package/src/index.js +5 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) STROMCOM
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# @stromcom/react-snippet
|
|
2
|
+
|
|
3
|
+
React integration for the [STROMCOM](https://www.stromcom.cz) chat widget. Loads the SDK, identifies users, and embeds threads as plain React components.
|
|
4
|
+
|
|
5
|
+
Plain JavaScript with hand-written TypeScript declarations — works in JS and TS projects, no transpilation surprises.
|
|
6
|
+
|
|
7
|
+
The matching backend helper is [`stromcom/php-snippet`](https://github.com/stromcom/php-snippet) — it hashes user/thread codes server-side (which you must do).
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
- React **17+**
|
|
12
|
+
- A pair of `clientKey` / `clientSecret` from the STROMCOM dashboard
|
|
13
|
+
- A backend that can hash codes (typically `stromcom/php-snippet`)
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @stromcom/react-snippet
|
|
19
|
+
# or
|
|
20
|
+
pnpm add @stromcom/react-snippet
|
|
21
|
+
# or
|
|
22
|
+
yarn add @stromcom/react-snippet
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick start
|
|
26
|
+
|
|
27
|
+
Wrap your app in `<StromcomProvider>`. It injects the loader script once and exposes the `stromCom` API to children. Components below queue their calls synchronously, so you don't need to wait for the loader to be ready.
|
|
28
|
+
|
|
29
|
+
```jsx
|
|
30
|
+
import {
|
|
31
|
+
StromcomProvider,
|
|
32
|
+
StromcomConf,
|
|
33
|
+
StromcomUser,
|
|
34
|
+
StromcomThread,
|
|
35
|
+
StromcomHome,
|
|
36
|
+
} from '@stromcom/react-snippet';
|
|
37
|
+
|
|
38
|
+
export default function App() {
|
|
39
|
+
return (
|
|
40
|
+
<StromcomProvider clientKey="your-client-key" clientSecret="your-bearer-token">
|
|
41
|
+
<StromcomConf
|
|
42
|
+
notificationElementPosition={4}
|
|
43
|
+
onNotification={(count) => console.log('unread:', count)}
|
|
44
|
+
/>
|
|
45
|
+
|
|
46
|
+
<StromcomUser code={user.stromcomHash} name={user.name} emailAddress={user.email} />
|
|
47
|
+
|
|
48
|
+
<StromcomThread
|
|
49
|
+
code={order.stromcomHash}
|
|
50
|
+
name={`Order #${order.id}`}
|
|
51
|
+
url={typeof window !== 'undefined' ? window.location.href : undefined}
|
|
52
|
+
style={{ height: 500 }}
|
|
53
|
+
/>
|
|
54
|
+
|
|
55
|
+
<StromcomHome style={{ position: 'fixed', bottom: 24, right: 24 }} />
|
|
56
|
+
</StromcomProvider>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Mental model — what runs once vs. many times
|
|
62
|
+
|
|
63
|
+
This is the most common confusion, so it's worth being explicit.
|
|
64
|
+
|
|
65
|
+
| Component | How many times in app | Where to put it | Runs |
|
|
66
|
+
| -------------------- | --------------------------------------------- | ------------------------------------------------------ | --------------------------------------------------------- |
|
|
67
|
+
| `<StromcomProvider>` | **Exactly once** | Top of the tree (root layout / `_app.js` / `main.jsx`) | Injects the loader script |
|
|
68
|
+
| `<StromcomConf>` | **Exactly once** | Direct child of provider | Sends configuration |
|
|
69
|
+
| `<StromcomUser>` | **Exactly once** at a time (per current user) | Direct child of provider | Identifies the user; re-runs when props change |
|
|
70
|
+
| `<StromcomThread>` | **Many times** — one per conversation | Anywhere inside provider | Renders one thread; **cannot** be re-initialized in place |
|
|
71
|
+
| `<StromcomHome>` | **Once** typically | Anywhere inside provider | Renders the notification center |
|
|
72
|
+
|
|
73
|
+
Think of it this way: provider, conf, and user are **app-level singletons**. Threads are **per-resource** — one per order, ticket, article, document, room… whatever your unit of conversation is. You can render five threads on a single page and dozens across the app.
|
|
74
|
+
|
|
75
|
+
### What's app-level, what's per-resource
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
StromcomProvider ← once
|
|
79
|
+
├─ StromcomConf ← once (configuration)
|
|
80
|
+
├─ StromcomUser ← once (current user)
|
|
81
|
+
├─ StromcomHome ← once (notification UI)
|
|
82
|
+
└─ ...routes...
|
|
83
|
+
├─ /orders/123 → StromcomThread code={hash('order-123')}
|
|
84
|
+
├─ /orders/456 → StromcomThread code={hash('order-456')}
|
|
85
|
+
└─ /article/x → StromcomThread code={hash('article-x')}
|
|
86
|
+
StromcomThread code={hash('article-x-internal')}
|
|
87
|
+
StromcomThread code={hash('article-x-customer')}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Multi-page apps (React Router, Next.js, Remix)
|
|
91
|
+
|
|
92
|
+
**The provider stays mounted the whole time** — put it in your root layout. Routes come and go below it. Each route renders its own `<StromcomThread>` for whatever resource it's showing. The widget script loads only once for the whole session.
|
|
93
|
+
|
|
94
|
+
You do **not** need to re-mount the provider on navigation, and you do **not** need a separate provider per route. See [`examples/03-multi-page-router.jsx`](./examples/03-multi-page-router.jsx).
|
|
95
|
+
|
|
96
|
+
### Multiple threads on the same page
|
|
97
|
+
|
|
98
|
+
Just render `<StromcomThread>` multiple times with different `code`s. Each div hosts one independent conversation. Useful for:
|
|
99
|
+
|
|
100
|
+
- A page with internal-team and customer-facing threads side by side
|
|
101
|
+
- A list view (e.g. comments on each row)
|
|
102
|
+
- A document with section-level discussions
|
|
103
|
+
|
|
104
|
+
See [`examples/06-multiple-threads-per-page.jsx`](./examples/06-multiple-threads-per-page.jsx).
|
|
105
|
+
|
|
106
|
+
### Anonymous / public pages
|
|
107
|
+
|
|
108
|
+
`<StromcomUser>` is optional. Skip it when there's no logged-in user — threads work read/write according to the dashboard's anonymous policy. Re-mount it the moment a visitor logs in. See [`examples/04-anonymous-then-login.jsx`](./examples/04-anonymous-then-login.jsx).
|
|
109
|
+
|
|
110
|
+
## Hashing user & thread codes — IMPORTANT
|
|
111
|
+
|
|
112
|
+
`code` values for `StromcomUser` and `StromcomThread` should be **hard to guess**. Hashing must happen **on your backend** (the secret cannot live in the browser).
|
|
113
|
+
|
|
114
|
+
Use the matching PHP package [`stromcom/php-snippet`](https://github.com/stromcom/php-snippet) (or any HMAC-SHA256 + base-62 implementation) to hash IDs server-side, then pass the hash through your API to React:
|
|
115
|
+
|
|
116
|
+
```php
|
|
117
|
+
// Backend (PHP)
|
|
118
|
+
$client = SnippetClientFactory::create(
|
|
119
|
+
clientKey: 'your-client-key',
|
|
120
|
+
clientSecret: 'your-bearer-token',
|
|
121
|
+
codeHashSecret: 'your-app-secret',
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
$hashedUserCode = $client->hashCode('user-id-42'); // ~43 chars
|
|
125
|
+
$hashedThreadCode = $client->hashCode('order-12345');
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```jsx
|
|
129
|
+
// Frontend (React)
|
|
130
|
+
<StromcomUser code={hashedUserCode} name="Jane" />
|
|
131
|
+
<StromcomThread code={hashedThreadCode} />
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Never pass raw internal IDs from the client.
|
|
135
|
+
|
|
136
|
+
## API
|
|
137
|
+
|
|
138
|
+
### `<StromcomProvider>`
|
|
139
|
+
|
|
140
|
+
| Prop | Type | Required | Description |
|
|
141
|
+
| -------------- | ----------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
142
|
+
| `clientKey` | `string` | ✅ | Project client key. |
|
|
143
|
+
| `clientSecret` | `string` | ✅ | Project bearer token. |
|
|
144
|
+
| `environment` | `"production"` \| `"staging"` \| `string` | | Default `"production"`. Pass any custom URL to point at a self-hosted loader. |
|
|
145
|
+
| `dataLayer` | `string` | | Default `"stromCom"`. The global JS variable name. Change it if `stromCom` collides with something else on the page. |
|
|
146
|
+
|
|
147
|
+
### `<StromcomUser>`
|
|
148
|
+
|
|
149
|
+
Identifies the logged-in user. Re-calls `initUser` whenever any prop changes. Renders nothing.
|
|
150
|
+
|
|
151
|
+
| Prop | Type | Required | Description |
|
|
152
|
+
| -------------- | --------- | -------- | ------------------------------------------------------- |
|
|
153
|
+
| `code` | `string` | ✅ | Hashed user identifier. Max 100 chars, `[a-zA-Z0-9-_]`. |
|
|
154
|
+
| `name` | `string` | | Display name. |
|
|
155
|
+
| `emailAddress` | `string` | | Used for email notifications. |
|
|
156
|
+
| `readOnly` | `boolean` | | When `true`, user can read but not send messages. |
|
|
157
|
+
| `avatarURL` | `string` | | Full avatar URL. |
|
|
158
|
+
|
|
159
|
+
### `<StromcomThread>`
|
|
160
|
+
|
|
161
|
+
Renders a `<div>` and embeds a thread into it. Initialized once on mount; threads cannot be re-initialized in place. To switch the thread shown by the same DOM node, change React's `key` so a fresh div is mounted.
|
|
162
|
+
|
|
163
|
+
Accepts `className`, `style`, and any `data-*` attributes.
|
|
164
|
+
|
|
165
|
+
| Prop | Type | Required | Description |
|
|
166
|
+
| ---------- | --------- | -------- | --------------------------------------------------------- |
|
|
167
|
+
| `code` | `string` | ✅ | Hashed thread identifier. Max 100 chars, `[a-zA-Z0-9-_]`. |
|
|
168
|
+
| `name` | `string` | | Display name shown in the thread header. |
|
|
169
|
+
| `url` | `string` | | Canonical URL — appears as a link in the header. |
|
|
170
|
+
| `userHint` | `boolean` | | Enable @mention suggestions. Default `true`. |
|
|
171
|
+
|
|
172
|
+
### `<StromcomHome>`
|
|
173
|
+
|
|
174
|
+
Renders a `<div>` and embeds the notification center into it.
|
|
175
|
+
|
|
176
|
+
| Prop | Type | Description |
|
|
177
|
+
| ----------- | -------- | -------------------------------- |
|
|
178
|
+
| `className` | `string` | CSS class for the container. |
|
|
179
|
+
| `style` | `object` | Inline styles for the container. |
|
|
180
|
+
|
|
181
|
+
### `<StromcomConf>`
|
|
182
|
+
|
|
183
|
+
Sends SDK configuration. Place once inside the provider, before threads.
|
|
184
|
+
|
|
185
|
+
Notable options:
|
|
186
|
+
|
|
187
|
+
| Prop | Type | Description |
|
|
188
|
+
| ----------------------------- | ----------------------------------------- | --------------------------------------------- |
|
|
189
|
+
| `notificationRenderer` | `Function` | Custom notification rendering function. |
|
|
190
|
+
| `onNotification` | `Function` | Called when unread count changes. |
|
|
191
|
+
| `pageCSSPath` | `string` | CSS file URL injected into the widget iframe. |
|
|
192
|
+
| `notificationElementPosition` | `1\|2\|3\|4` | Icon position: 1=TL, 2=TR, 3=BR, 4=BL. |
|
|
193
|
+
| `theme` | `"stromcom-light"\|"stromcom-dark"\|null` | Theme. `null` follows browser preference. |
|
|
194
|
+
|
|
195
|
+
See [`src/StromcomConf.jsx`](./src/StromcomConf.jsx) for the full list.
|
|
196
|
+
|
|
197
|
+
### `useStromcom()` — escape hatch
|
|
198
|
+
|
|
199
|
+
Returns the global `stromCom` object directly. Use when you need to call something the components don't expose (e.g. switching the active user from a button click).
|
|
200
|
+
|
|
201
|
+
```jsx
|
|
202
|
+
import { useStromcom } from '@stromcom/react-snippet';
|
|
203
|
+
|
|
204
|
+
function SwitchUserButton() {
|
|
205
|
+
const sc = useStromcom();
|
|
206
|
+
return <button onClick={() => sc?.initUser({ code: 'newHashedCode' })}>Switch user</button>;
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Examples
|
|
211
|
+
|
|
212
|
+
The [`examples/`](./examples) folder has focused, copy-pasteable snippets for the common patterns:
|
|
213
|
+
|
|
214
|
+
| File | Scenario |
|
|
215
|
+
| --------------------------------------------------------------------------------- | -------------------------------------------------- |
|
|
216
|
+
| [`01-basic-app.jsx`](./examples/01-basic-app.jsx) | Minimal setup — provider + user + one thread |
|
|
217
|
+
| [`02-nextjs-app-router/`](./examples/02-nextjs-app-router) | Next.js 13+ App Router with server-side hashing |
|
|
218
|
+
| [`03-multi-page-router.jsx`](./examples/03-multi-page-router.jsx) | React Router — provider in root, thread per route |
|
|
219
|
+
| [`04-anonymous-then-login.jsx`](./examples/04-anonymous-then-login.jsx) | Public site, user mounts only after login |
|
|
220
|
+
| [`05-conditional-thread.jsx`](./examples/05-conditional-thread.jsx) | Thread inside a modal / opens on demand |
|
|
221
|
+
| [`06-multiple-threads-per-page.jsx`](./examples/06-multiple-threads-per-page.jsx) | Several threads on one page (per-row, per-section) |
|
|
222
|
+
| [`07-imperative-api.jsx`](./examples/07-imperative-api.jsx) | `useStromcom()` for switch-user / logout flows |
|
|
223
|
+
| [`08-theme-switcher.jsx`](./examples/08-theme-switcher.jsx) | Toggling between light/dark theme at runtime |
|
|
224
|
+
| [`09-staging-environment.jsx`](./examples/09-staging-environment.jsx) | Pointing at staging or a custom loader URL |
|
|
225
|
+
| [`10-php-backend-integration.md`](./examples/10-php-backend-integration.md) | End-to-end with PHP backend providing hashes |
|
|
226
|
+
|
|
227
|
+
## SSR / Next.js
|
|
228
|
+
|
|
229
|
+
The provider is SSR-safe — it only touches `window` inside `useEffect`. The loader script is appended on the client. No special wrapping needed in Next.js, Remix, etc.
|
|
230
|
+
|
|
231
|
+
For the App Router, mount `<StromcomProvider>` in a Client Component placed inside your root layout. Server Components above it stay server-rendered. See [`examples/02-nextjs-app-router/`](./examples/02-nextjs-app-router).
|
|
232
|
+
|
|
233
|
+
## Troubleshooting
|
|
234
|
+
|
|
235
|
+
**The loader script never appears.** Check that `clientKey` and `clientSecret` are non-empty. The provider does nothing on the server.
|
|
236
|
+
|
|
237
|
+
**Thread is empty / blank div.** Verify the `code` prop. Make sure it's the hashed value coming from your backend, not the raw internal ID.
|
|
238
|
+
|
|
239
|
+
**Thread doesn't update when I change props.** By design — threads can't be re-initialized in place. Pass a different React `key` to force a remount.
|
|
240
|
+
|
|
241
|
+
**Two providers warn / double script.** Don't mount the provider twice. The provider deduplicates the `<script>` tag, but mounting two providers with different `clientKey`s is unsupported.
|
|
242
|
+
|
|
243
|
+
**Notification count never fires.** Make sure `<StromcomConf onNotification={...}>` is mounted as a child of the provider, and that `<StromcomUser>` runs (notifications are user-scoped).
|
|
244
|
+
|
|
245
|
+
## License
|
|
246
|
+
|
|
247
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/index.js
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
|
+
StromcomConf: () => StromcomConf,
|
|
23
|
+
StromcomHome: () => StromcomHome,
|
|
24
|
+
StromcomProvider: () => StromcomProvider,
|
|
25
|
+
StromcomThread: () => StromcomThread,
|
|
26
|
+
StromcomUser: () => StromcomUser,
|
|
27
|
+
useStromcom: () => useStromcom
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(index_exports);
|
|
30
|
+
|
|
31
|
+
// src/StromcomProvider.jsx
|
|
32
|
+
var import_react = require("react");
|
|
33
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
34
|
+
var StromcomContext = (0, import_react.createContext)(null);
|
|
35
|
+
var LOADER_URLS = {
|
|
36
|
+
production: "https://cdn.stromcom.cz/loader.js",
|
|
37
|
+
staging: "https://cdn.staging.stromcom.cz/loader.js"
|
|
38
|
+
};
|
|
39
|
+
function setupLayer(dataLayer) {
|
|
40
|
+
var _a;
|
|
41
|
+
if (typeof window === "undefined") {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
if ((_a = window[dataLayer]) == null ? void 0 : _a.__sc_ready) {
|
|
45
|
+
return window[dataLayer];
|
|
46
|
+
}
|
|
47
|
+
const dl = dataLayer + "DL";
|
|
48
|
+
window[dl] = window[dl] || {};
|
|
49
|
+
window[dataLayer] = window[dataLayer] || {};
|
|
50
|
+
const layer = window[dataLayer];
|
|
51
|
+
const stub = (method, dlKey, isArray) => {
|
|
52
|
+
dlKey = dlKey || method;
|
|
53
|
+
if (isArray) {
|
|
54
|
+
window[dl][dlKey] = window[dl][dlKey] || [];
|
|
55
|
+
}
|
|
56
|
+
layer[method] = (...args) => {
|
|
57
|
+
if (isArray) {
|
|
58
|
+
window[dl][dlKey].push(args);
|
|
59
|
+
} else {
|
|
60
|
+
window[dl][dlKey] = args;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
stub("initUser", "user");
|
|
65
|
+
stub("thread", "threads", true);
|
|
66
|
+
stub("conf");
|
|
67
|
+
stub("home", "home", true);
|
|
68
|
+
layer.__sc_ready = true;
|
|
69
|
+
return layer;
|
|
70
|
+
}
|
|
71
|
+
function StromcomProvider({
|
|
72
|
+
clientKey,
|
|
73
|
+
clientSecret,
|
|
74
|
+
dataLayer = "stromCom",
|
|
75
|
+
environment = "production",
|
|
76
|
+
children
|
|
77
|
+
}) {
|
|
78
|
+
const layer = setupLayer(dataLayer);
|
|
79
|
+
(0, import_react.useEffect)(() => {
|
|
80
|
+
var _a;
|
|
81
|
+
if (typeof window === "undefined") return;
|
|
82
|
+
if (document.querySelector(`script[data-ck="${clientKey}"][data-type="stromcom"]`)) return;
|
|
83
|
+
const base = (_a = LOADER_URLS[environment]) != null ? _a : environment;
|
|
84
|
+
const dl = dataLayer + "DL";
|
|
85
|
+
const script = document.createElement("script");
|
|
86
|
+
script.async = true;
|
|
87
|
+
script.dataset.type = "stromcom";
|
|
88
|
+
script.dataset.l = dataLayer;
|
|
89
|
+
script.dataset.dl = dl;
|
|
90
|
+
script.dataset.ck = clientKey;
|
|
91
|
+
script.dataset.cs = clientSecret;
|
|
92
|
+
script.src = `${base}?${clientKey}`;
|
|
93
|
+
document.head.appendChild(script);
|
|
94
|
+
return () => script.remove();
|
|
95
|
+
}, [clientKey, clientSecret, dataLayer, environment]);
|
|
96
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StromcomContext.Provider, { value: layer, children });
|
|
97
|
+
}
|
|
98
|
+
function useStromcom() {
|
|
99
|
+
return (0, import_react.useContext)(StromcomContext);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/StromcomUser.jsx
|
|
103
|
+
var import_react2 = require("react");
|
|
104
|
+
function StromcomUser({ code, name, emailAddress, readOnly, avatarURL }) {
|
|
105
|
+
const sc = useStromcom();
|
|
106
|
+
(0, import_react2.useEffect)(() => {
|
|
107
|
+
if (!sc) return;
|
|
108
|
+
const opts = { code };
|
|
109
|
+
if (name !== void 0) opts.name = name;
|
|
110
|
+
if (emailAddress !== void 0) opts.emailAddress = emailAddress;
|
|
111
|
+
if (readOnly !== void 0) opts.readOnly = readOnly;
|
|
112
|
+
if (avatarURL !== void 0) opts.avatarURL = avatarURL;
|
|
113
|
+
sc.initUser(opts);
|
|
114
|
+
}, [sc, code, name, emailAddress, readOnly, avatarURL]);
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/StromcomConf.jsx
|
|
119
|
+
var import_react3 = require("react");
|
|
120
|
+
function StromcomConf({
|
|
121
|
+
notificationRenderer,
|
|
122
|
+
onNotification,
|
|
123
|
+
pageCSSPath,
|
|
124
|
+
notificationElementTargetElement,
|
|
125
|
+
notificationElementShowAlways,
|
|
126
|
+
notificationElementPosition,
|
|
127
|
+
notificationElementStyles,
|
|
128
|
+
notificationElementCSSPath,
|
|
129
|
+
notificationElementNoShadowRoot,
|
|
130
|
+
homeBeforeRender,
|
|
131
|
+
notificationElementBeforeRender,
|
|
132
|
+
notificationElementAfterRender,
|
|
133
|
+
theme
|
|
134
|
+
}) {
|
|
135
|
+
const sc = useStromcom();
|
|
136
|
+
(0, import_react3.useEffect)(() => {
|
|
137
|
+
if (!sc) return;
|
|
138
|
+
const opts = {};
|
|
139
|
+
if (notificationRenderer !== void 0) opts.notificationRenderer = notificationRenderer;
|
|
140
|
+
if (onNotification !== void 0) opts.onNotification = onNotification;
|
|
141
|
+
if (pageCSSPath !== void 0) opts.pageCSSPath = pageCSSPath;
|
|
142
|
+
if (notificationElementTargetElement !== void 0)
|
|
143
|
+
opts.notificationElementTargetElement = notificationElementTargetElement;
|
|
144
|
+
if (notificationElementShowAlways !== void 0)
|
|
145
|
+
opts.notificationElementShowAlways = notificationElementShowAlways;
|
|
146
|
+
if (notificationElementPosition !== void 0)
|
|
147
|
+
opts.notificationElementPosition = notificationElementPosition;
|
|
148
|
+
if (notificationElementStyles !== void 0)
|
|
149
|
+
opts.notificationElementStyles = notificationElementStyles;
|
|
150
|
+
if (notificationElementCSSPath !== void 0)
|
|
151
|
+
opts.notificationElementCSSPath = notificationElementCSSPath;
|
|
152
|
+
if (notificationElementNoShadowRoot !== void 0)
|
|
153
|
+
opts.notificationElementNoShadowRoot = notificationElementNoShadowRoot;
|
|
154
|
+
if (homeBeforeRender !== void 0) opts.homeBeforeRender = homeBeforeRender;
|
|
155
|
+
if (notificationElementBeforeRender !== void 0)
|
|
156
|
+
opts.notificationElementBeforeRender = notificationElementBeforeRender;
|
|
157
|
+
if (notificationElementAfterRender !== void 0)
|
|
158
|
+
opts.notificationElementAfterRender = notificationElementAfterRender;
|
|
159
|
+
if (theme !== void 0) opts.theme = theme;
|
|
160
|
+
sc.conf(opts);
|
|
161
|
+
}, [
|
|
162
|
+
sc,
|
|
163
|
+
notificationRenderer,
|
|
164
|
+
onNotification,
|
|
165
|
+
pageCSSPath,
|
|
166
|
+
notificationElementTargetElement,
|
|
167
|
+
notificationElementShowAlways,
|
|
168
|
+
notificationElementPosition,
|
|
169
|
+
notificationElementStyles,
|
|
170
|
+
notificationElementCSSPath,
|
|
171
|
+
notificationElementNoShadowRoot,
|
|
172
|
+
homeBeforeRender,
|
|
173
|
+
notificationElementBeforeRender,
|
|
174
|
+
notificationElementAfterRender,
|
|
175
|
+
theme
|
|
176
|
+
]);
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// src/StromcomThread.jsx
|
|
181
|
+
var import_react4 = require("react");
|
|
182
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
183
|
+
function StromcomThread({ code, name, url, userHint, className, style, ...rest }) {
|
|
184
|
+
const sc = useStromcom();
|
|
185
|
+
const containerRef = (0, import_react4.useRef)(null);
|
|
186
|
+
const initializedRef = (0, import_react4.useRef)(false);
|
|
187
|
+
(0, import_react4.useEffect)(() => {
|
|
188
|
+
if (!sc || !containerRef.current || initializedRef.current) return;
|
|
189
|
+
const opts = { code };
|
|
190
|
+
if (name !== void 0) opts.name = name;
|
|
191
|
+
if (url !== void 0) opts.url = url;
|
|
192
|
+
if (userHint !== void 0) opts.userHint = userHint;
|
|
193
|
+
sc.thread(containerRef.current, opts);
|
|
194
|
+
initializedRef.current = true;
|
|
195
|
+
}, [sc]);
|
|
196
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref: containerRef, className, style, ...rest });
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/StromcomHome.jsx
|
|
200
|
+
var import_react5 = require("react");
|
|
201
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
202
|
+
function StromcomHome({ className, style, ...rest }) {
|
|
203
|
+
const sc = useStromcom();
|
|
204
|
+
const containerRef = (0, import_react5.useRef)(null);
|
|
205
|
+
const initializedRef = (0, import_react5.useRef)(false);
|
|
206
|
+
(0, import_react5.useEffect)(() => {
|
|
207
|
+
if (!sc || !containerRef.current || initializedRef.current) return;
|
|
208
|
+
sc.home(containerRef.current);
|
|
209
|
+
initializedRef.current = true;
|
|
210
|
+
}, [sc]);
|
|
211
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: containerRef, className, style, ...rest });
|
|
212
|
+
}
|
|
213
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
214
|
+
0 && (module.exports = {
|
|
215
|
+
StromcomConf,
|
|
216
|
+
StromcomHome,
|
|
217
|
+
StromcomProvider,
|
|
218
|
+
StromcomThread,
|
|
219
|
+
StromcomUser,
|
|
220
|
+
useStromcom
|
|
221
|
+
});
|
|
222
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.js","../src/StromcomProvider.jsx","../src/StromcomUser.jsx","../src/StromcomConf.jsx","../src/StromcomThread.jsx","../src/StromcomHome.jsx"],"sourcesContent":["export { StromcomProvider, useStromcom } from './StromcomProvider.jsx';\nexport { StromcomUser } from './StromcomUser.jsx';\nexport { StromcomConf } from './StromcomConf.jsx';\nexport { StromcomThread } from './StromcomThread.jsx';\nexport { StromcomHome } from './StromcomHome.jsx';\n","import { createContext, useContext, useEffect } from 'react';\n\nexport const StromcomContext = createContext(null);\n\nconst LOADER_URLS = {\n production: 'https://cdn.stromcom.cz/loader.js',\n staging: 'https://cdn.staging.stromcom.cz/loader.js',\n};\n\n/**\n * Sets up the stromCom stub layer synchronously so that child components can\n * queue calls (initUser, thread, conf, home) before the async loader.js arrives.\n * Mirrors what the PHP snippet() method generates.\n */\nfunction setupLayer(dataLayer) {\n if (typeof window === 'undefined') {\n return null;\n }\n\n if (window[dataLayer]?.__sc_ready) {\n return window[dataLayer];\n }\n\n const dl = dataLayer + 'DL';\n window[dl] = window[dl] || {};\n window[dataLayer] = window[dataLayer] || {};\n const layer = window[dataLayer];\n\n const stub = (method, dlKey, isArray) => {\n dlKey = dlKey || method;\n if (isArray) {\n window[dl][dlKey] = window[dl][dlKey] || [];\n }\n\n layer[method] = (...args) => {\n if (isArray) {\n window[dl][dlKey].push(args);\n } else {\n window[dl][dlKey] = args;\n }\n };\n };\n\n stub('initUser', 'user');\n stub('thread', 'threads', true);\n stub('conf');\n stub('home', 'home', true);\n\n layer.__sc_ready = true;\n return layer;\n}\n\n/**\n * Wraps the app and loads the Stromcom widget SDK.\n *\n * @param {object} props\n * @param {string} props.clientKey - Client key from the Stromcom dashboard\n * @param {string} props.clientSecret - Bearer token from the Stromcom dashboard\n * @param {string} [props.dataLayer] - Global JS variable name (default: \"stromCom\")\n * @param {string} [props.environment] - \"production\" | \"staging\" | full custom loader URL\n * @param {React.ReactNode} props.children\n *\n * @example\n * <StromcomProvider clientKey=\"ck_xxx\" clientSecret=\"cs_xxx\">\n * <App />\n * </StromcomProvider>\n */\nexport function StromcomProvider({\n clientKey,\n clientSecret,\n dataLayer = 'stromCom',\n environment = 'production',\n children,\n}) {\n // Set up stubs synchronously so children can queue calls immediately on render.\n const layer = setupLayer(dataLayer);\n\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n // Avoid injecting the script twice (React StrictMode, HMR, etc.)\n if (document.querySelector(`script[data-ck=\"${clientKey}\"][data-type=\"stromcom\"]`)) return;\n\n const base = LOADER_URLS[environment] ?? environment;\n const dl = dataLayer + 'DL';\n\n const script = document.createElement('script');\n script.async = true;\n script.dataset.type = 'stromcom';\n script.dataset.l = dataLayer;\n script.dataset.dl = dl;\n script.dataset.ck = clientKey;\n script.dataset.cs = clientSecret;\n script.src = `${base}?${clientKey}`;\n document.head.appendChild(script);\n\n return () => script.remove();\n }, [clientKey, clientSecret, dataLayer, environment]);\n\n return <StromcomContext.Provider value={layer}>{children}</StromcomContext.Provider>;\n}\n\nexport function useStromcom() {\n return useContext(StromcomContext);\n}\n","import { useEffect } from 'react';\nimport { useStromcom } from './StromcomProvider.jsx';\n\n/**\n * Identifies the currently logged-in user.\n * Re-calls initUser whenever any prop changes.\n *\n * IMPORTANT: The `code` should already be hashed server-side (HMAC + base-62).\n * Never pass your raw internal user ID directly from the client.\n *\n * @param {object} props\n * @param {string} props.code - Hashed unique user identifier (max 100 chars, [a-zA-Z0-9-_])\n * @param {string} [props.name] - Display name\n * @param {string} [props.emailAddress]- Used for email notifications\n * @param {boolean} [props.readOnly] - When true, user can read but not send messages\n * @param {string} [props.avatarURL] - Full URL to avatar image\n *\n * @example\n * <StromcomUser\n * code={user.stromcomHash}\n * name={user.name}\n * emailAddress={user.email}\n * />\n */\nexport function StromcomUser({ code, name, emailAddress, readOnly, avatarURL }) {\n const sc = useStromcom();\n\n useEffect(() => {\n if (!sc) return;\n\n const opts = { code };\n if (name !== undefined) opts.name = name;\n if (emailAddress !== undefined) opts.emailAddress = emailAddress;\n if (readOnly !== undefined) opts.readOnly = readOnly;\n if (avatarURL !== undefined) opts.avatarURL = avatarURL;\n\n sc.initUser(opts);\n }, [sc, code, name, emailAddress, readOnly, avatarURL]);\n\n return null;\n}\n","import { useEffect } from 'react';\nimport { useStromcom } from './StromcomProvider.jsx';\n\n/**\n * Sends SDK configuration to the Stromcom widget.\n * Should be placed once inside <StromcomProvider>, before threads or the home component.\n * Re-sends conf whenever any option prop changes.\n *\n * Options that accept functions (notificationRenderer, onNotification, etc.) take\n * actual JS functions here — no need for the string-wrapping used in the PHP library.\n *\n * @param {object} [props.notificationRenderer] - Function(notification) for custom notification rendering\n * @param {object} [props.onNotification] - Function(count) called when unread count changes\n * @param {string} [props.pageCSSPath] - URL of CSS file injected into the widget iframe\n * @param {Function} [props.notificationElementTargetElement] - Function/Promise/Element returning the icon mount target\n * @param {boolean} [props.notificationElementShowAlways] - Show icon even with zero notifications\n * @param {number} [props.notificationElementPosition] - Icon position: 1=top-left 2=top-right 3=bottom-right 4=bottom-left\n * @param {object} [props.notificationElementStyles] - Inline styles object for the default notification button\n * @param {string} [props.notificationElementCSSPath] - CSS URL for the default notification renderer\n * @param {boolean} [props.notificationElementNoShadowRoot]- Disable shadow-root for notifications\n * @param {Function} [props.homeBeforeRender] - Callback before notification center opens\n * @param {Function} [props.notificationElementBeforeRender]- Callback before notification icon renders\n * @param {Function} [props.notificationElementAfterRender] - Callback after notification icon renders\n * @param {('stromcom-light'|'stromcom-dark'|null)} [props.theme] - Theme. null follows browser preference.\n *\n * @example\n * <StromcomConf\n * notificationElementPosition={4}\n * onNotification={(count) => setBadge(count)}\n * />\n */\nexport function StromcomConf({\n notificationRenderer,\n onNotification,\n pageCSSPath,\n notificationElementTargetElement,\n notificationElementShowAlways,\n notificationElementPosition,\n notificationElementStyles,\n notificationElementCSSPath,\n notificationElementNoShadowRoot,\n homeBeforeRender,\n notificationElementBeforeRender,\n notificationElementAfterRender,\n theme,\n}) {\n const sc = useStromcom();\n\n useEffect(() => {\n if (!sc) return;\n\n const opts = {};\n\n if (notificationRenderer !== undefined) opts.notificationRenderer = notificationRenderer;\n if (onNotification !== undefined) opts.onNotification = onNotification;\n if (pageCSSPath !== undefined) opts.pageCSSPath = pageCSSPath;\n if (notificationElementTargetElement !== undefined)\n opts.notificationElementTargetElement = notificationElementTargetElement;\n if (notificationElementShowAlways !== undefined)\n opts.notificationElementShowAlways = notificationElementShowAlways;\n if (notificationElementPosition !== undefined)\n opts.notificationElementPosition = notificationElementPosition;\n if (notificationElementStyles !== undefined)\n opts.notificationElementStyles = notificationElementStyles;\n if (notificationElementCSSPath !== undefined)\n opts.notificationElementCSSPath = notificationElementCSSPath;\n if (notificationElementNoShadowRoot !== undefined)\n opts.notificationElementNoShadowRoot = notificationElementNoShadowRoot;\n if (homeBeforeRender !== undefined) opts.homeBeforeRender = homeBeforeRender;\n if (notificationElementBeforeRender !== undefined)\n opts.notificationElementBeforeRender = notificationElementBeforeRender;\n if (notificationElementAfterRender !== undefined)\n opts.notificationElementAfterRender = notificationElementAfterRender;\n if (theme !== undefined) opts.theme = theme;\n\n sc.conf(opts);\n }, [\n sc,\n notificationRenderer,\n onNotification,\n pageCSSPath,\n notificationElementTargetElement,\n notificationElementShowAlways,\n notificationElementPosition,\n notificationElementStyles,\n notificationElementCSSPath,\n notificationElementNoShadowRoot,\n homeBeforeRender,\n notificationElementBeforeRender,\n notificationElementAfterRender,\n theme,\n ]);\n\n return null;\n}\n","import { useEffect, useRef } from 'react';\nimport { useStromcom } from './StromcomProvider.jsx';\n\n/**\n * Embeds a Stromcom conversation thread into the rendered div.\n * The thread is initialized once on mount.\n *\n * IMPORTANT: The `code` should already be hashed server-side (HMAC + base-62).\n *\n * @param {object} props\n * @param {string} props.code - Hashed unique thread identifier (max 100 chars, [a-zA-Z0-9-_])\n * @param {string} [props.name] - Display name shown in the thread header\n * @param {string} [props.url] - Canonical URL of the page (shown as link in header)\n * @param {boolean} [props.userHint] - Enable @mention suggestions (default: true)\n * @param {string} [props.className] - CSS class for the container div\n * @param {object} [props.style] - Inline styles for the container div\n *\n * @example\n * <StromcomThread\n * code={order.stromcomHash}\n * name={`Order #${order.id}`}\n * url={window.location.href}\n * style={{ height: '400px' }}\n * />\n */\nexport function StromcomThread({ code, name, url, userHint, className, style, ...rest }) {\n const sc = useStromcom();\n const containerRef = useRef(null);\n const initializedRef = useRef(false);\n\n useEffect(() => {\n if (!sc || !containerRef.current || initializedRef.current) return;\n\n const opts = { code };\n if (name !== undefined) opts.name = name;\n if (url !== undefined) opts.url = url;\n if (userHint !== undefined) opts.userHint = userHint;\n\n sc.thread(containerRef.current, opts);\n initializedRef.current = true;\n // eslint-disable-next-line react-hooks/exhaustive-deps -- intentionally omit option deps, thread cannot be re-initialized\n }, [sc]);\n\n return <div ref={containerRef} className={className} style={style} {...rest} />;\n}\n","import { useEffect, useRef } from 'react';\nimport { useStromcom } from './StromcomProvider.jsx';\n\n/**\n * Embeds the Stromcom notification center into the rendered div.\n * Initialized once on mount.\n *\n * @param {object} [props.className] - CSS class for the container div\n * @param {object} [props.style] - Inline styles for the container div\n *\n * @example\n * <StromcomHome style={{ position: 'fixed', bottom: 24, right: 24 }} />\n */\nexport function StromcomHome({ className, style, ...rest }) {\n const sc = useStromcom();\n const containerRef = useRef(null);\n const initializedRef = useRef(false);\n\n useEffect(() => {\n if (!sc || !containerRef.current || initializedRef.current) return;\n sc.home(containerRef.current);\n initializedRef.current = true;\n }, [sc]);\n\n return <div ref={containerRef} className={className} style={style} {...rest} />;\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export type StromcomEnvironment = 'production' | 'staging' | (string & {});
|
|
4
|
+
|
|
5
|
+
export interface StromcomLayer {
|
|
6
|
+
initUser: (options: StromcomUserOptions) => void;
|
|
7
|
+
thread: (target: HTMLElement, options: StromcomThreadOptions) => void;
|
|
8
|
+
conf: (options: StromcomConfOptions) => void;
|
|
9
|
+
home: (target: HTMLElement) => void;
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface StromcomProviderProps {
|
|
14
|
+
/** Project client key from the Stromcom dashboard. */
|
|
15
|
+
clientKey: string;
|
|
16
|
+
/** Bearer token / client secret from the Stromcom dashboard. */
|
|
17
|
+
clientSecret: string;
|
|
18
|
+
/** Global JS variable name. Default `"stromCom"`. */
|
|
19
|
+
dataLayer?: string;
|
|
20
|
+
/** `"production"`, `"staging"`, or a full custom loader URL. Default `"production"`. */
|
|
21
|
+
environment?: StromcomEnvironment;
|
|
22
|
+
children?: ReactNode;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function StromcomProvider(props: StromcomProviderProps): JSX.Element;
|
|
26
|
+
|
|
27
|
+
/** Returns the global stromCom object once the loader is set up (or `null` server-side). */
|
|
28
|
+
export function useStromcom(): StromcomLayer | null;
|
|
29
|
+
|
|
30
|
+
export interface StromcomUserOptions {
|
|
31
|
+
/** Hashed unique user identifier (max 100 chars, [a-zA-Z0-9-_]). Hash server-side. */
|
|
32
|
+
code: string;
|
|
33
|
+
name?: string;
|
|
34
|
+
emailAddress?: string;
|
|
35
|
+
readOnly?: boolean;
|
|
36
|
+
avatarURL?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function StromcomUser(props: StromcomUserOptions): null;
|
|
40
|
+
|
|
41
|
+
export interface StromcomThreadOptions {
|
|
42
|
+
/** Hashed unique thread identifier (max 100 chars, [a-zA-Z0-9-_]). Hash server-side. */
|
|
43
|
+
code: string;
|
|
44
|
+
name?: string;
|
|
45
|
+
url?: string;
|
|
46
|
+
/** Enable @mention suggestions. Default `true`. */
|
|
47
|
+
userHint?: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface StromcomThreadProps extends StromcomThreadOptions {
|
|
51
|
+
className?: string;
|
|
52
|
+
style?: CSSProperties;
|
|
53
|
+
[key: `data-${string}`]: string | number | boolean | undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function StromcomThread(props: StromcomThreadProps): JSX.Element;
|
|
57
|
+
|
|
58
|
+
export interface StromcomHomeProps {
|
|
59
|
+
className?: string;
|
|
60
|
+
style?: CSSProperties;
|
|
61
|
+
[key: `data-${string}`]: string | number | boolean | undefined;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function StromcomHome(props: StromcomHomeProps): JSX.Element;
|
|
65
|
+
|
|
66
|
+
export interface StromcomConfOptions {
|
|
67
|
+
notificationRenderer?: (notification: unknown) => unknown;
|
|
68
|
+
onNotification?: (count: number) => void;
|
|
69
|
+
pageCSSPath?: string;
|
|
70
|
+
notificationElementTargetElement?:
|
|
71
|
+
(() => HTMLElement | Promise<HTMLElement>) | HTMLElement | Promise<HTMLElement>;
|
|
72
|
+
notificationElementShowAlways?: boolean;
|
|
73
|
+
/** Icon position: 1=top-left, 2=top-right, 3=bottom-right, 4=bottom-left. */
|
|
74
|
+
notificationElementPosition?: 1 | 2 | 3 | 4;
|
|
75
|
+
notificationElementStyles?: Record<string, string | number | null>;
|
|
76
|
+
notificationElementCSSPath?: string;
|
|
77
|
+
notificationElementNoShadowRoot?: boolean;
|
|
78
|
+
homeBeforeRender?: () => void | Promise<void>;
|
|
79
|
+
notificationElementBeforeRender?: () => void | Promise<void>;
|
|
80
|
+
notificationElementAfterRender?: () => void;
|
|
81
|
+
/** Theme: `"stromcom-light"`, `"stromcom-dark"`, or `null` to follow browser preference. */
|
|
82
|
+
theme?: 'stromcom-light' | 'stromcom-dark' | null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function StromcomConf(props: StromcomConfOptions): null;
|