@manufosela/slide-notification 2.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/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # @manufosela/slide-notification
2
+
3
+ Slide-in notification web component from the right edge. Built with [Lit](https://lit.dev/).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @manufosela/slide-notification
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```javascript
14
+ import { showSlideNotification } from '@manufosela/slide-notification';
15
+
16
+ // Simple notification
17
+ showSlideNotification({
18
+ message: 'Hello, world!'
19
+ });
20
+
21
+ // With type and title
22
+ showSlideNotification({
23
+ type: 'success',
24
+ title: 'Success!',
25
+ message: 'Your changes have been saved.'
26
+ });
27
+ ```
28
+
29
+ ## Features
30
+
31
+ - Slides in from the right edge
32
+ - Four notification types (info, success, warning, error)
33
+ - Auto-hide with configurable duration
34
+ - HTML message support
35
+ - Custom background colors
36
+ - CSS custom properties for theming
37
+
38
+ ## Attributes
39
+
40
+ | Attribute | Type | Default | Description |
41
+ | ------------------ | ------- | ------- | ------------------------------ |
42
+ | `title` | String | `''` | Notification title |
43
+ | `message` | String | `''` | Message (supports HTML) |
44
+ | `type` | String | `info` | Type: info, success, warning, error |
45
+ | `timetohide` | Number | `3000` | Auto-hide delay in ms (0 = never) |
46
+ | `background-color` | String | `''` | Custom background color |
47
+ | `persistent` | Boolean | `false` | Stay visible until clicked |
48
+
49
+ ## Methods
50
+
51
+ | Method | Description |
52
+ | -------- | ---------------------------------------- |
53
+ | `show()` | Show the notification |
54
+ | `hide()` | Hide the notification |
55
+
56
+ ## Events
57
+
58
+ | Event | Description |
59
+ | ---------------------------- | ------------------------------ |
60
+ | `slide-notification-shown` | Fired when notification appears |
61
+ | `slide-notification-hidden` | Fired when notification hides |
62
+
63
+ ## Notification Types
64
+
65
+ ```javascript
66
+ // Info (default) - Blue
67
+ showSlideNotification({ type: 'info', message: 'Info message' });
68
+
69
+ // Success - Green/Blue
70
+ showSlideNotification({ type: 'success', message: 'Success!' });
71
+
72
+ // Warning - Yellow (dark text)
73
+ showSlideNotification({ type: 'warning', message: 'Warning!' });
74
+
75
+ // Error - Red
76
+ showSlideNotification({ type: 'error', message: 'Error occurred' });
77
+ ```
78
+
79
+ ## Custom Duration
80
+
81
+ ```javascript
82
+ // Quick notification (1 second)
83
+ showSlideNotification({
84
+ message: 'Quick!',
85
+ timetohide: 1000
86
+ });
87
+
88
+ // Persistent (click to close)
89
+ showSlideNotification({
90
+ message: 'Click me to close',
91
+ persistent: true
92
+ });
93
+ ```
94
+
95
+ ## Declarative Usage
96
+
97
+ For manual control, use the element in HTML:
98
+
99
+ ```html
100
+ <slide-notification id="myNotification"
101
+ title="Hello"
102
+ message="Click buttons to control"
103
+ persistent>
104
+ </slide-notification>
105
+
106
+ <button onclick="myNotification.show()">Show</button>
107
+ <button onclick="myNotification.hide()">Hide</button>
108
+ ```
109
+
110
+ ## Custom Colors
111
+
112
+ ```javascript
113
+ showSlideNotification({
114
+ message: 'Purple notification',
115
+ backgroundColor: '#8b5cf6'
116
+ });
117
+ ```
118
+
119
+ ## CSS Custom Properties
120
+
121
+ | Property | Default | Description |
122
+ | --------------------------------- | ------------------------------ | ------------------ |
123
+ | `--slide-notification-width` | `300px` | Notification width |
124
+ | `--slide-notification-bg` | `#17a2b8` | Background color |
125
+ | `--slide-notification-color` | `white` | Text color |
126
+ | `--slide-notification-radius` | `8px` | Border radius |
127
+ | `--slide-notification-padding` | `1.5rem` | Padding |
128
+ | `--slide-notification-shadow` | `0 2px 8px rgba(0,0,0,0.2)` | Box shadow |
129
+ | `--slide-notification-bottom` | `20px` | Bottom position |
130
+ | `--slide-notification-z-index` | `10000` | Z-index |
131
+ | `--slide-notification-min-height` | `80px` | Minimum height |
132
+
133
+ ## slide-notification vs toast-notification
134
+
135
+ This library includes two notification components. Choose based on your needs:
136
+
137
+ | Feature | slide-notification | toast-notification |
138
+ |---------|--------------------|-------------------|
139
+ | **Animation** | Slides in from right edge | Appears in corner |
140
+ | **Position** | Right side only | 6 positions (corners + centers) |
141
+ | **Stacking** | One at a time | Multiple stack vertically |
142
+ | **Progress bar** | No | Yes |
143
+ | **Close button** | No (click anywhere) | Yes |
144
+ | **Persistent mode** | `persistent` attribute | `duration="0"` |
145
+ | **Best for** | Single important messages | Multiple sequential notifications |
146
+
147
+ **Use `slide-notification` when:**
148
+ - You want a prominent single notification
149
+ - You prefer slide-in animation
150
+ - You want click-anywhere-to-close behavior
151
+
152
+ **Use `toast-notification` when:**
153
+ - You need to show multiple notifications
154
+ - You want position flexibility (6 options)
155
+ - You need a progress bar indicator
156
+
157
+ ## License
158
+
159
+ MIT
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@manufosela/slide-notification",
3
+ "version": "2.0.0",
4
+ "description": "Slide-in notification web component from the right edge",
5
+ "main": "src/slide-notification.js",
6
+ "module": "src/slide-notification.js",
7
+ "type": "module",
8
+ "files": [
9
+ "src"
10
+ ],
11
+ "scripts": {
12
+ "start": "web-dev-server --node-resolve --open demo/ --watch",
13
+ "test": "web-test-runner",
14
+ "test:watch": "web-test-runner --watch",
15
+ "test:coverage": "web-test-runner --coverage"
16
+ },
17
+ "keywords": [
18
+ "web-components",
19
+ "lit",
20
+ "notification",
21
+ "slide",
22
+ "toast",
23
+ "alert"
24
+ ],
25
+ "author": "manufosela",
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/manufosela/ui-components",
30
+ "directory": "packages/slide-notification"
31
+ },
32
+ "homepage": "https://github.com/manufosela/ui-components/tree/main/packages/slide-notification#readme",
33
+ "bugs": {
34
+ "url": "https://github.com/manufosela/ui-components/issues"
35
+ },
36
+ "dependencies": {
37
+ "lit": "^3.2.1"
38
+ },
39
+ "devDependencies": {
40
+ "@open-wc/testing": "^4.0.0",
41
+ "@web/dev-server": "^0.4.6",
42
+ "@web/test-runner": "^0.19.0"
43
+ }
44
+ }
@@ -0,0 +1,208 @@
1
+ import { LitElement, html } from 'lit';
2
+ import { unsafeHTML } from 'lit/directives/unsafe-html.js';
3
+ import { slideNotificationStyles } from './slide-notification.styles.js';
4
+
5
+ const DEFAULT_COLORS = {
6
+ error: '#dc3545',
7
+ success: '#22c55e',
8
+ warning: '#ffc107',
9
+ info: '#17a2b8'
10
+ };
11
+
12
+ const ICONS = {
13
+ error: '❌',
14
+ success: '✅',
15
+ warning: '⚠️',
16
+ info: 'ℹ️'
17
+ };
18
+
19
+ /**
20
+ * A slide-in notification component from the right edge.
21
+ *
22
+ * @element slide-notification
23
+ * @fires slide-notification-shown - Fired when notification appears
24
+ * @fires slide-notification-hidden - Fired when notification is hidden
25
+ *
26
+ * @attr {String} title - Notification title
27
+ * @attr {String} message - Notification message (supports HTML)
28
+ * @attr {Number} timetohide - Time in ms before auto-hide (default: 3000, 0 = persistent)
29
+ * @attr {String} type - Type: 'info', 'success', 'warning', 'error'
30
+ * @attr {String} background-color - Custom background color
31
+ * @attr {Boolean} persistent - If true, notification stays until clicked (same as timetohide=0)
32
+ *
33
+ * @cssprop --slide-notification-width - Width (default: 300px)
34
+ * @cssprop --slide-notification-bg - Background color (default: #17a2b8)
35
+ * @cssprop --slide-notification-color - Text color (default: white)
36
+ * @cssprop --slide-notification-radius - Border radius (default: 8px)
37
+ * @cssprop --slide-notification-z-index - Z-index (default: 10000)
38
+ */
39
+ export class SlideNotification extends LitElement {
40
+ static styles = slideNotificationStyles;
41
+
42
+ static properties = {
43
+ title: { type: String },
44
+ message: { type: String },
45
+ timetohide: { type: Number },
46
+ backgroundColor: { type: String, attribute: 'background-color' },
47
+ type: { type: String, reflect: true },
48
+ persistent: { type: Boolean, reflect: true },
49
+ };
50
+
51
+ constructor() {
52
+ super();
53
+ this.title = '';
54
+ this.message = '';
55
+ this.timetohide = 3000;
56
+ this.type = 'info';
57
+ this.backgroundColor = '';
58
+ this.persistent = false;
59
+ this._hideTimeout = null;
60
+ this._isVisible = false;
61
+ this._createdProgrammatically = false;
62
+ this._removeOnHide = false;
63
+ }
64
+
65
+ connectedCallback() {
66
+ super.connectedCallback();
67
+
68
+ // Click to close for persistent notifications
69
+ this.addEventListener('click', this._handleClick);
70
+
71
+ // Only auto-show if created programmatically (via helper function)
72
+ if (this._createdProgrammatically) {
73
+ this._showNotification();
74
+ }
75
+ }
76
+
77
+ _showNotification() {
78
+ if (this._isVisible) return;
79
+ this._isVisible = true;
80
+
81
+ requestAnimationFrame(() => {
82
+ requestAnimationFrame(() => {
83
+ this.classList.remove('hiding');
84
+ this.classList.add('visible');
85
+
86
+ this.dispatchEvent(new CustomEvent('slide-notification-shown', {
87
+ bubbles: true,
88
+ composed: true
89
+ }));
90
+ });
91
+
92
+ // Auto-hide after timeout (unless persistent)
93
+ const shouldAutoHide = !this.persistent && this.timetohide > 0;
94
+ if (shouldAutoHide) {
95
+ this._hideTimeout = setTimeout(() => {
96
+ this.hide();
97
+ }, this.timetohide);
98
+ }
99
+ });
100
+ }
101
+
102
+ _handleClick = () => {
103
+ if (this.persistent || this.timetohide === 0) {
104
+ this.hide();
105
+ }
106
+ }
107
+
108
+ disconnectedCallback() {
109
+ super.disconnectedCallback();
110
+ if (this._hideTimeout) {
111
+ clearTimeout(this._hideTimeout);
112
+ this._hideTimeout = null;
113
+ }
114
+ this.removeEventListener('click', this._handleClick);
115
+ }
116
+
117
+ hide() {
118
+ if (!this._isVisible) return;
119
+ this._isVisible = false;
120
+
121
+ if (this._hideTimeout) {
122
+ clearTimeout(this._hideTimeout);
123
+ this._hideTimeout = null;
124
+ }
125
+
126
+ this.classList.remove('visible');
127
+ this.classList.add('hiding');
128
+
129
+ this.dispatchEvent(new CustomEvent('slide-notification-hidden', {
130
+ bubbles: true,
131
+ composed: true
132
+ }));
133
+
134
+ // Remove from DOM if created programmatically
135
+ if (this._removeOnHide) {
136
+ setTimeout(() => this.remove(), 600);
137
+ }
138
+ }
139
+
140
+ show() {
141
+ this._showNotification();
142
+ }
143
+
144
+ _getBackgroundColor() {
145
+ if (this.backgroundColor) return this.backgroundColor;
146
+ return DEFAULT_COLORS[this.type] || DEFAULT_COLORS.info;
147
+ }
148
+
149
+ _getTextColor() {
150
+ return this.type === 'warning' ? '#212529' : 'white';
151
+ }
152
+
153
+ _getTextShadow() {
154
+ return this.type === 'warning'
155
+ ? '1px 1px 2px rgba(0, 0, 0, 0.3)'
156
+ : '1px 1px 2px rgba(0, 0, 0, 0.5)';
157
+ }
158
+
159
+ render() {
160
+ const icon = ICONS[this.type] || ICONS.info;
161
+ const bgColor = this._getBackgroundColor();
162
+ const textColor = this._getTextColor();
163
+ const textShadow = this._getTextShadow();
164
+
165
+ this.style.setProperty('--_bg', bgColor);
166
+ this.style.setProperty('--_color', textColor);
167
+ this.style.setProperty('--_text-shadow', textShadow);
168
+
169
+ return html`
170
+ ${this.title ? html`<div class="title">${this.title}</div>` : ''}
171
+ <div class="notification-content">
172
+ <span class="icon">${icon}</span>
173
+ <div class="message">${unsafeHTML(this.message)}</div>
174
+ </div>
175
+ `;
176
+ }
177
+ }
178
+
179
+ customElements.define('slide-notification', SlideNotification);
180
+
181
+ /**
182
+ * Helper function to show a slide notification
183
+ * @param {Object} options - Notification options
184
+ * @param {string} options.title - Notification title
185
+ * @param {string} options.message - Notification message (supports HTML)
186
+ * @param {number} options.timetohide - Time in ms before auto-hide (default: 3000, 0 = persistent)
187
+ * @param {string} options.type - Type: 'info' | 'success' | 'warning' | 'error'
188
+ * @param {string} options.backgroundColor - Custom background color
189
+ * @param {boolean} options.persistent - If true, stays until clicked
190
+ * @returns {SlideNotification} The created notification element
191
+ */
192
+ export function showSlideNotification(options = {}) {
193
+ const notification = document.createElement('slide-notification');
194
+ notification.title = options.title || '';
195
+ notification.message = options.message || 'Notification';
196
+ notification.timetohide = options.timetohide ?? 3000;
197
+ notification.type = options.type || 'info';
198
+ notification.persistent = options.persistent || false;
199
+ if (options.backgroundColor) {
200
+ notification.backgroundColor = options.backgroundColor;
201
+ }
202
+
203
+ // Mark as programmatically created so it auto-shows and auto-removes
204
+ notification._createdProgrammatically = true;
205
+ notification._removeOnHide = true;
206
+ document.body.appendChild(notification);
207
+ return notification;
208
+ }
@@ -0,0 +1,67 @@
1
+ import { css } from 'lit';
2
+
3
+ export const slideNotificationStyles = css`
4
+ :host {
5
+ --_width: var(--slide-notification-width, 300px);
6
+ --_bg: var(--slide-notification-bg, #17a2b8);
7
+ --_color: var(--slide-notification-color, white);
8
+ --_text-shadow: var(--slide-notification-text-shadow, 1px 1px 2px rgba(0, 0, 0, 0.5));
9
+
10
+ position: fixed;
11
+ bottom: var(--slide-notification-bottom, 20px);
12
+ right: calc(-20px - var(--_width));
13
+ width: var(--_width);
14
+ min-height: var(--slide-notification-min-height, 80px);
15
+ background: var(--_bg);
16
+ color: var(--_color);
17
+ border-radius: var(--slide-notification-radius, 8px);
18
+ border-left: 4px solid rgba(255, 255, 255, 0.3);
19
+ padding: var(--slide-notification-padding, 1.5rem);
20
+ box-shadow: var(--slide-notification-shadow, 0 2px 8px rgba(0, 0, 0, 0.2));
21
+ font-size: 1rem;
22
+ font-weight: 500;
23
+ opacity: 0;
24
+ transition: transform 0.5s ease-in-out, opacity 0.5s ease-in-out;
25
+ transform: translateX(0);
26
+ z-index: var(--slide-notification-z-index, 10000);
27
+ display: flex;
28
+ flex-direction: column;
29
+ justify-content: center;
30
+ align-items: center;
31
+ }
32
+
33
+ :host(.visible) {
34
+ opacity: 1;
35
+ transform: translateX(calc(-1 * var(--_width) - 40px));
36
+ }
37
+
38
+ :host(.hiding) {
39
+ transform: translateX(calc(var(--_width) + 40px));
40
+ }
41
+
42
+ :host([persistent]) {
43
+ cursor: pointer;
44
+ }
45
+
46
+ .title {
47
+ font-weight: 600;
48
+ margin-bottom: 0.25rem;
49
+ text-shadow: var(--_text-shadow);
50
+ }
51
+
52
+ .notification-content {
53
+ display: flex;
54
+ align-items: center;
55
+ gap: 0.5rem;
56
+ }
57
+
58
+ .message {
59
+ font-weight: 500;
60
+ text-shadow: var(--_text-shadow);
61
+ }
62
+
63
+ .icon {
64
+ font-size: 1.2em;
65
+ flex-shrink: 0;
66
+ }
67
+ `;