@dismissible/react-client 0.0.1-canary.10
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/README.md +435 -0
- package/dist/dismissible-client.es.js +834 -0
- package/dist/dismissible-client.umd.js +22 -0
- package/dist/mockServiceWorker.js +344 -0
- package/dist/style.css +1 -0
- package/package.json +81 -0
package/README.md
ADDED
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
# @dismissible/react-client
|
|
2
|
+
|
|
3
|
+
A React component library for creating dismissible UI elements with persistent state management.
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/@dismissible%2Freact-client)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🎯 **Easy to use** - Simple component API for dismissible content
|
|
11
|
+
- 💾 **Persistent state** - Dismissal state is saved and restored across sessions
|
|
12
|
+
- 🎨 **Customizable** - Custom loading, error, and dismiss button components
|
|
13
|
+
- ♿ **Accessible** - Built with accessibility best practices
|
|
14
|
+
- 🪝 **Hook-based** - Includes `useDismissibleItem` hook for custom implementations
|
|
15
|
+
- 📦 **Lightweight** - Minimal bundle size with tree-shaking support
|
|
16
|
+
- 🔧 **TypeScript** - Full TypeScript support with complete type definitions
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @dismissible/react-client
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Peer Dependencies
|
|
25
|
+
|
|
26
|
+
Make sure you have React 18+ installed:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install react react-dom
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import React from 'react';
|
|
36
|
+
import { Dismissible } from '@dismissible/react-client';
|
|
37
|
+
|
|
38
|
+
function App() {
|
|
39
|
+
return (
|
|
40
|
+
<Dismissible id="welcome-banner-123-413-31-1">
|
|
41
|
+
<div className="banner">
|
|
42
|
+
<h2>Welcome to our app!</h2>
|
|
43
|
+
<p>This banner can be dismissed and won't show again.</p>
|
|
44
|
+
</div>
|
|
45
|
+
</Dismissible>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## API Reference
|
|
51
|
+
|
|
52
|
+
### `<Dismissible>` Component
|
|
53
|
+
|
|
54
|
+
The main component for creating dismissible content.
|
|
55
|
+
|
|
56
|
+
#### Props
|
|
57
|
+
|
|
58
|
+
| Prop | Type | Required | Description |
|
|
59
|
+
|------|------|----------|-------------|
|
|
60
|
+
| `id` | `string` | ✅ | Unique identifier for the dismissible item |
|
|
61
|
+
| `children` | `ReactNode` | ✅ | Content to render when not dismissed |
|
|
62
|
+
| `onDismiss` | `() => void` | ❌ | Callback fired when item is dismissed |
|
|
63
|
+
| `LoadingComponent` | `ComponentType<{id: string}>` | ❌ | Custom loading component |
|
|
64
|
+
| `ErrorComponent` | `ComponentType<{id: string, error: Error}>` | ❌ | Custom error component |
|
|
65
|
+
| `DismissButtonComponent` | `ComponentType<{id: string, onDismiss: () => Promise<void>, ariaLabel: string}>` | ❌ | Custom dismiss button |
|
|
66
|
+
|
|
67
|
+
#### Example
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
<Dismissible
|
|
71
|
+
id="promo-banner"
|
|
72
|
+
onDismiss={() => console.log('Banner dismissed')}
|
|
73
|
+
onRestore={() => console.log('Banner restored')}
|
|
74
|
+
>
|
|
75
|
+
<div className="promo">
|
|
76
|
+
<h3>Special Offer!</h3>
|
|
77
|
+
<p>Get 50% off your first order</p>
|
|
78
|
+
</div>
|
|
79
|
+
</Dismissible>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### `useDismissibleItem` Hook
|
|
83
|
+
|
|
84
|
+
For custom implementations and advanced use cases.
|
|
85
|
+
|
|
86
|
+
#### Parameters
|
|
87
|
+
|
|
88
|
+
| Parameter | Type | Required | Description |
|
|
89
|
+
|-----------|------|----------|-------------|
|
|
90
|
+
| `id` | `string` | ✅ | Unique identifier for the dismissible item |
|
|
91
|
+
|
|
92
|
+
#### Returns
|
|
93
|
+
|
|
94
|
+
| Property | Type | Description |
|
|
95
|
+
|----------|------|-------------|
|
|
96
|
+
| `dismissedOn` | `string \| null` | ISO date string when item was dismissed, or null |
|
|
97
|
+
| `dismiss` | `() => Promise<void>` | Function to dismiss the item |
|
|
98
|
+
| `isLoading` | `boolean` | Loading state indicator |
|
|
99
|
+
| `error` | `Error \| null` | Error state, if any |
|
|
100
|
+
|
|
101
|
+
#### Example
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import { useDismissibleItem } from '@dismissible/react-client';
|
|
105
|
+
|
|
106
|
+
function CustomDismissible({ id, children }) {
|
|
107
|
+
const { dismissedOn, dismiss, isLoading, error } = useDismissibleItem(id);
|
|
108
|
+
|
|
109
|
+
if (dismissedOn) {
|
|
110
|
+
return null; // Item is dismissed
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (isLoading) {
|
|
114
|
+
return <div>Loading...</div>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (error) {
|
|
118
|
+
return <div>Error: {error.message}</div>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<div>
|
|
123
|
+
{children}
|
|
124
|
+
<button onClick={dismiss}>
|
|
125
|
+
Dismiss
|
|
126
|
+
</button>
|
|
127
|
+
</div>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Usage Examples
|
|
133
|
+
|
|
134
|
+
### Basic Dismissible Banner
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
import { Dismissible } from '@dismissible/react-client';
|
|
138
|
+
|
|
139
|
+
function WelcomeBanner() {
|
|
140
|
+
return (
|
|
141
|
+
<Dismissible id="welcome-banner-234-432-432-1">
|
|
142
|
+
<div className="alert alert-info">
|
|
143
|
+
<h4>Welcome!</h4>
|
|
144
|
+
<p>Thanks for joining our platform. Here are some quick tips to get started.</p>
|
|
145
|
+
</div>
|
|
146
|
+
</Dismissible>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Custom Dismiss Button
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
import { Dismissible } from '@dismissible/react-client';
|
|
155
|
+
|
|
156
|
+
const CustomDismissButton = ({ onDismiss, ariaLabel }) => (
|
|
157
|
+
<button
|
|
158
|
+
onClick={onDismiss}
|
|
159
|
+
className="custom-close-btn"
|
|
160
|
+
aria-label={ariaLabel}
|
|
161
|
+
>
|
|
162
|
+
✕
|
|
163
|
+
</button>
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
function CustomBanner() {
|
|
167
|
+
return (
|
|
168
|
+
<Dismissible
|
|
169
|
+
id="custom-banner"
|
|
170
|
+
DismissButtonComponent={CustomDismissButton}
|
|
171
|
+
>
|
|
172
|
+
<div className="banner">
|
|
173
|
+
<p>This banner has a custom dismiss button!</p>
|
|
174
|
+
</div>
|
|
175
|
+
</Dismissible>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Custom Loading and Error Components
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
import { Dismissible } from '@dismissible/react-client';
|
|
184
|
+
|
|
185
|
+
const CustomLoader = ({ id }) => (
|
|
186
|
+
<div className="spinner">
|
|
187
|
+
<div className="bounce1"></div>
|
|
188
|
+
<div className="bounce2"></div>
|
|
189
|
+
<div className="bounce3"></div>
|
|
190
|
+
</div>
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
const CustomError = ({ error }) => (
|
|
194
|
+
<div className="error-card">
|
|
195
|
+
<h4>Oops! Something went wrong</h4>
|
|
196
|
+
<p>{error.message}</p>
|
|
197
|
+
<button onClick={() => window.location.reload()}>
|
|
198
|
+
Try Again
|
|
199
|
+
</button>
|
|
200
|
+
</div>
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
function AdvancedBanner() {
|
|
204
|
+
return (
|
|
205
|
+
<Dismissible
|
|
206
|
+
id="advanced-banner"
|
|
207
|
+
LoadingComponent={CustomLoader}
|
|
208
|
+
ErrorComponent={CustomError}
|
|
209
|
+
>
|
|
210
|
+
<div className="banner">
|
|
211
|
+
<p>This banner has custom loading and error states!</p>
|
|
212
|
+
</div>
|
|
213
|
+
</Dismissible>
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Multiple Dismissible Items
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
import { Dismissible } from '@dismissible/react-client';
|
|
222
|
+
|
|
223
|
+
function Dashboard() {
|
|
224
|
+
return (
|
|
225
|
+
<div>
|
|
226
|
+
<Dismissible id="feature-announcement-234-432-432-1">
|
|
227
|
+
<div className="alert alert-success">
|
|
228
|
+
🎉 New feature: Dark mode is now available!
|
|
229
|
+
</div>
|
|
230
|
+
</Dismissible>
|
|
231
|
+
|
|
232
|
+
<Dismissible id="maintenance-notice-234-432-432-1">
|
|
233
|
+
<div className="alert alert-warning">
|
|
234
|
+
⚠️ Scheduled maintenance: Sunday 2AM-4AM EST
|
|
235
|
+
</div>
|
|
236
|
+
</Dismissible>
|
|
237
|
+
|
|
238
|
+
<Dismissible id="survey-request-234-432-432-1">
|
|
239
|
+
<div className="alert alert-info">
|
|
240
|
+
📝 Help us improve! Take our 2-minute survey.
|
|
241
|
+
</div>
|
|
242
|
+
</Dismissible>
|
|
243
|
+
</div>
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Conditional Dismissible Content
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
import { Dismissible } from '@dismissible/react-client';
|
|
252
|
+
|
|
253
|
+
function ConditionalBanner({ user }) {
|
|
254
|
+
// Only show to new users
|
|
255
|
+
if (user.isReturning) {
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return (
|
|
260
|
+
<Dismissible id={`onboarding-${user.id}`}>
|
|
261
|
+
<div className="onboarding-tips">
|
|
262
|
+
<h3>Getting Started</h3>
|
|
263
|
+
<ul>
|
|
264
|
+
<li>Complete your profile</li>
|
|
265
|
+
<li>Connect with friends</li>
|
|
266
|
+
<li>Explore our features</li>
|
|
267
|
+
</ul>
|
|
268
|
+
</div>
|
|
269
|
+
</Dismissible>
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Using the Hook for Complex Logic
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
import { useDismissibleItem } from '@dismissible/react-client';
|
|
278
|
+
import { useState, useEffect } from 'react';
|
|
279
|
+
|
|
280
|
+
function SmartNotification({ id, message, type = 'info' }) {
|
|
281
|
+
const { dismissedOn, dismiss, isLoading } = useDismissibleItem(id);
|
|
282
|
+
const [autoHide, setAutoHide] = useState(false);
|
|
283
|
+
|
|
284
|
+
// Auto-hide after 10 seconds for info messages
|
|
285
|
+
useEffect(() => {
|
|
286
|
+
if (type === 'info' && !dismissedOn) {
|
|
287
|
+
const timer = setTimeout(() => {
|
|
288
|
+
setAutoHide(true);
|
|
289
|
+
dismiss();
|
|
290
|
+
}, 10000);
|
|
291
|
+
|
|
292
|
+
return () => clearTimeout(timer);
|
|
293
|
+
}
|
|
294
|
+
}, [type, dismissedOn, dismiss]);
|
|
295
|
+
|
|
296
|
+
if (dismissedOn || autoHide) {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return (
|
|
301
|
+
<div className={`notification notification-${type}`}>
|
|
302
|
+
<span>{message}</span>
|
|
303
|
+
<button
|
|
304
|
+
onClick={dismiss}
|
|
305
|
+
disabled={isLoading}
|
|
306
|
+
className="dismiss-btn"
|
|
307
|
+
>
|
|
308
|
+
{isLoading ? '...' : '×'}
|
|
309
|
+
</button>
|
|
310
|
+
</div>
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## Styling
|
|
316
|
+
|
|
317
|
+
The library includes minimal default styles. You can override them or provide your own:
|
|
318
|
+
|
|
319
|
+
```css
|
|
320
|
+
/* Default classes you can style */
|
|
321
|
+
.dismissible-container {
|
|
322
|
+
/* Container for the dismissible content */
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.dismissible-loading {
|
|
326
|
+
/* Loading state */
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.dismissible-error {
|
|
330
|
+
/* Error state */
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.dismissible-dismiss-btn {
|
|
334
|
+
/* Default dismiss button */
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## TypeScript Support
|
|
339
|
+
|
|
340
|
+
The library is written in TypeScript and exports all type definitions:
|
|
341
|
+
|
|
342
|
+
```tsx
|
|
343
|
+
import type {
|
|
344
|
+
DismissibleProps,
|
|
345
|
+
IDismissibleItem
|
|
346
|
+
} from '@dismissible/react-client';
|
|
347
|
+
|
|
348
|
+
const MyComponent: React.FC<DismissibleProps> = (props) => {
|
|
349
|
+
// Your component implementation
|
|
350
|
+
};
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## Development
|
|
354
|
+
|
|
355
|
+
### Prerequisites
|
|
356
|
+
|
|
357
|
+
- Node.js 18+
|
|
358
|
+
- npm or yarn
|
|
359
|
+
|
|
360
|
+
### Setup
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
# Clone the repository
|
|
364
|
+
git clone https://github.com/your-org/dismissible.git
|
|
365
|
+
cd dismissible/react-client
|
|
366
|
+
|
|
367
|
+
# Install dependencies
|
|
368
|
+
npm install
|
|
369
|
+
|
|
370
|
+
# Start development server
|
|
371
|
+
npm run dev
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### Available Scripts
|
|
375
|
+
|
|
376
|
+
- `npm run dev` - Start development server with Vite
|
|
377
|
+
- `npm run build` - Build the library for production
|
|
378
|
+
- `npm run test` - Run tests with Vitest
|
|
379
|
+
- `npm run test:watch` - Run tests in watch mode
|
|
380
|
+
- `npm run lint` - Run ESLint
|
|
381
|
+
- `npm run format` - Format code with Prettier
|
|
382
|
+
- `npm run storybook` - Start Storybook development server
|
|
383
|
+
- `npm run build-storybook` - Build Storybook for production
|
|
384
|
+
|
|
385
|
+
### Testing
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
# Run all tests
|
|
389
|
+
npm run test
|
|
390
|
+
|
|
391
|
+
# Run tests in watch mode
|
|
392
|
+
npm run test:watch
|
|
393
|
+
|
|
394
|
+
# Run tests with coverage
|
|
395
|
+
npm run test -- --coverage
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
### Storybook
|
|
399
|
+
|
|
400
|
+
The library includes Storybook for component development and documentation:
|
|
401
|
+
|
|
402
|
+
```bash
|
|
403
|
+
npm run storybook
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
## Contributing
|
|
407
|
+
|
|
408
|
+
We welcome contributions! Please see our [Contributing Guide](../CONTRIBUTING.md) for details.
|
|
409
|
+
|
|
410
|
+
### Development Workflow
|
|
411
|
+
|
|
412
|
+
1. Fork the repository
|
|
413
|
+
2. Create a feature branch: `git checkout -b feature/my-new-feature`
|
|
414
|
+
3. Make your changes
|
|
415
|
+
4. Add tests for new functionality
|
|
416
|
+
5. Run tests: `npm run test`
|
|
417
|
+
6. Run linting: `npm run lint`
|
|
418
|
+
7. Commit your changes: `git commit -am 'Add new feature'`
|
|
419
|
+
8. Push to the branch: `git push origin feature/my-new-feature`
|
|
420
|
+
9. Submit a pull request
|
|
421
|
+
|
|
422
|
+
## License
|
|
423
|
+
|
|
424
|
+
MIT © [Your Organization](https://github.com/your-org)
|
|
425
|
+
|
|
426
|
+
## Support
|
|
427
|
+
|
|
428
|
+
- 📖 [Documentation](https://docs.dismissible.io)
|
|
429
|
+
- 🐛 [Issue Tracker](https://github.com/your-org/dismissible/issues)
|
|
430
|
+
- 💬 [Discussions](https://github.com/your-org/dismissible/discussions)
|
|
431
|
+
- 📧 [Email Support](mailto:support@dismissible.io)
|
|
432
|
+
|
|
433
|
+
## Changelog
|
|
434
|
+
|
|
435
|
+
See [CHANGELOG.md](./CHANGELOG.md) for a detailed list of changes.
|