kitzo 2.0.32 → 2.0.33

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 CHANGED
@@ -25,7 +25,7 @@ npm i kitzo
25
25
  or
26
26
 
27
27
  ```javascript
28
- <script src="https://cdn.jsdelivr.net/npm/kitzo@2.0.32/dist/kitzo.umd.min.js"></script>
28
+ <script src="https://cdn.jsdelivr.net/npm/kitzo@2.0.33/dist/kitzo.umd.min.js"></script>
29
29
  ```
30
30
 
31
31
  > Attach this script tag in the html head tag and you are good to go.
@@ -157,8 +157,8 @@ import { ToastContainer, toast, ... } from 'kitzo/react';
157
157
  ```jsx
158
158
  import { toast } from 'kitzo/react';
159
159
 
160
- toast.success('toast message', { duration: 2000, style: {}, showIcon: true });
161
- toast.error('toast message', { duration: 2000, style: {}, showIcon: true });
160
+ toast.success('toast message', { duration: 2000, style: {}, showIcon: true, position: 'top-center' });
161
+ toast.error('toast message', { duration: 2000, style: {}, showIcon: true, position: 'top-center' });
162
162
 
163
163
  toast.promise(
164
164
  promise(), // call a function that returns promise
@@ -167,11 +167,11 @@ toast.promise(
167
167
  success: 'Saved' | (response) => 'Saved',
168
168
  error: 'Error occured' | (error) => 'Error occured',
169
169
  },
170
- { duration: 2000, style: {}, showIcon: true },
170
+ { duration: 2000, style: {}, showIcon: true, position: 'top-center' },
171
171
  );
172
172
 
173
173
  // JSX element
174
- toast.custom(<MyCustomComponent />, { duration: 2000 });
174
+ toast.custom(<MyCustomComponent />, { duration: 2000, position: 'top-center' });
175
175
 
176
176
  // Function that receives a dismiss handler
177
177
  toast.custom((dismiss) => (
@@ -187,6 +187,7 @@ toast.custom("string");
187
187
 
188
188
  ##### Toast API Usage
189
189
 
190
+
190
191
  ```jsx
191
192
  import { ToastContainer, toast } from 'kitzo/react';
192
193
 
@@ -207,7 +208,7 @@ function App() {
207
208
  success: 'Data saved',
208
209
  error: 'Failed saving data',
209
210
  },
210
- { duration: 2500 },
211
+ { duration: 2500, position: 'top-center' },
211
212
  );
212
213
  }
213
214
 
@@ -221,6 +222,7 @@ function App() {
221
222
  ),
222
223
  {
223
224
  duration: 2000,
225
+ position: 'top-center',
224
226
  },
225
227
  );
226
228
  }
@@ -233,8 +235,9 @@ function App() {
233
235
  <button onClick={customToast}>Custom Toast</button>
234
236
 
235
237
  {/* Toast container must needed */}
236
- <ToastContainer position="top-center" />
238
+ <ToastContainer />
237
239
  </div>
238
240
  );
239
241
  }
240
242
  ```
243
+ > Each toast can have its own position, but if you specify a position on `<ToastContainer />`, that position will apply to all toasts.
package/dist/react.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
 
3
3
  export interface ToastOptions {
4
+ position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
4
5
  duration?: number;
5
6
  style?: React.CSSProperties;
6
7
  showIcon?: boolean;
@@ -20,9 +21,9 @@ export interface ToastAPI {
20
21
  },
21
22
  options?: ToastOptions,
22
23
  ): Promise<T>;
23
- custom(content: CustomContent, options?: { duration?: number | Infinity; exitDelay?: number }): void;
24
+ custom(content: CustomContent, options?: { duration?: number; exitDelay?: number; position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right' }): void;
24
25
  }
25
26
 
26
27
  export declare const toast: ToastAPI;
27
28
 
28
- export declare function ToastContainer(props: { position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'; gap?: number }): JSX.Element;
29
+ export declare function ToastContainer(props: { position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'; gap?: number }): void;
package/dist/react.esm.js CHANGED
@@ -204,6 +204,7 @@ function subscribe(callback) {
204
204
  function success(text = 'Toast success', options = {}) {
205
205
  const id = Date.now();
206
206
  options = Object.assign({
207
+ position: 'top-center',
207
208
  duration: 2000,
208
209
  id,
209
210
  style: {},
@@ -218,6 +219,7 @@ function success(text = 'Toast success', options = {}) {
218
219
  function error(text = 'Toast denied', options = {}) {
219
220
  const id = Date.now();
220
221
  options = Object.assign({
222
+ position: 'top-center',
221
223
  duration: 2000,
222
224
  id,
223
225
  style: {},
@@ -232,6 +234,7 @@ function error(text = 'Toast denied', options = {}) {
232
234
  function promise(callback, msgs = {}, options = {}) {
233
235
  const id = Date.now();
234
236
  options = Object.assign({
237
+ position: 'top-center',
235
238
  duration: 2000,
236
239
  id,
237
240
  style: {},
@@ -273,6 +276,7 @@ function promise(callback, msgs = {}, options = {}) {
273
276
  function custom(render, options = {}) {
274
277
  const id = Date.now();
275
278
  options = Object.assign({
279
+ position: 'top-center',
276
280
  duration: 3000,
277
281
  id,
278
282
  exitDelay: 50
@@ -366,10 +370,12 @@ function Toast({
366
370
  } = options;
367
371
  const ref = useRef(null);
368
372
  useLayoutEffect(() => {
369
- const height = ref.current.getBoundingClientRect().height + gap;
370
- setToasts(prev => prev.map(t => t.id == id ? {
373
+ if (!ref.current) return;
374
+ const height = ref.current.getBoundingClientRect().height;
375
+ const totalHeight = height + gap;
376
+ setToasts(prev => prev.map(t => t.id === id ? {
371
377
  ...t,
372
- height
378
+ height: totalHeight
373
379
  } : t));
374
380
  }, []);
375
381
  const transformY = position.includes('bottom') ? `translateY(-${offset || 0}px)` : `translateY(${offset || 0}px)`;
@@ -422,14 +428,15 @@ function getToastPosition(position) {
422
428
 
423
429
  function ToastContainer(props) {
424
430
  props = Object.assign({
425
- position: 'top-center',
426
431
  gap: 8
427
432
  }, props);
428
433
  const {
429
- position,
430
434
  gap
431
435
  } = props;
436
+ const position = props.position;
432
437
  const [toasts, setToasts] = useState([]);
438
+
439
+ // event listener
433
440
  useEffect(() => {
434
441
  const unsub = subscribe(toast => {
435
442
  if (toast.type === 'dismiss') {
@@ -476,19 +483,33 @@ function ToastContainer(props) {
476
483
  });
477
484
  return () => unsub();
478
485
  }, []);
479
- useEffect(() => {
480
- let offset = 0;
486
+
487
+ // measue height and offset for each toast
488
+ useLayoutEffect(() => {
489
+ const grouped = toasts.reduce((acc, t) => {
490
+ const pos = t.options.position || position || 'top-center';
491
+ (acc[pos] ||= []).push(t);
492
+ return acc;
493
+ }, {});
494
+ let hasChanged = false;
481
495
  const updated = toasts.map(toast => {
482
- const top = offset;
483
- offset += toast.height;
496
+ const pos = toast.options.position || position || 'top-center';
497
+ const group = grouped[pos];
498
+ const index = group.findIndex(t => t.id === toast.id);
499
+ const offset = group.slice(0, index).reduce((acc, t) => acc + (t.height || 0), 0);
500
+ if (offset !== toast.offset) {
501
+ hasChanged = true;
502
+ }
484
503
  return {
485
504
  ...toast,
486
- offset: top
505
+ offset
487
506
  };
488
507
  });
489
- const changed = updated.some((u, i) => u.offset != toasts[i].offset);
490
- if (changed) setToasts(updated);
508
+ if (hasChanged) {
509
+ setToasts(updated);
510
+ }
491
511
  }, [toasts]);
512
+ const positions = ['top-left', 'top-center', 'top-right', 'bottom-left', 'bottom-center', 'bottom-right'];
492
513
  return /*#__PURE__*/React.createElement("div", {
493
514
  style: {
494
515
  position: 'fixed',
@@ -496,10 +517,15 @@ function ToastContainer(props) {
496
517
  zIndex: 100000000,
497
518
  pointerEvents: 'none',
498
519
  fontFamily: 'inherit',
499
- display: 'grid',
500
- padding: '1rem',
501
520
  boxSizing: 'border-box'
502
521
  }
522
+ }, position ? /*#__PURE__*/React.createElement("div", {
523
+ style: {
524
+ position: 'absolute',
525
+ inset: 0,
526
+ display: 'grid',
527
+ padding: '1rem'
528
+ }
503
529
  }, /*#__PURE__*/React.createElement("div", {
504
530
  style: {
505
531
  position: 'relative'
@@ -510,7 +536,29 @@ function ToastContainer(props) {
510
536
  setToasts: setToasts,
511
537
  position: position,
512
538
  gap: typeof gap === 'string' ? isNaN(+gap) ? 8 : +gap : gap
513
- }))));
539
+ })))) : /*#__PURE__*/React.createElement(React.Fragment, null, positions.map(pos => {
540
+ const group = toasts.filter(t => t.options.position === pos);
541
+ if (!group.length) return null;
542
+ return /*#__PURE__*/React.createElement("div", {
543
+ key: pos,
544
+ style: {
545
+ position: 'absolute',
546
+ inset: 0,
547
+ display: 'grid',
548
+ padding: '1rem'
549
+ }
550
+ }, /*#__PURE__*/React.createElement("div", {
551
+ style: {
552
+ position: 'relative'
553
+ }
554
+ }, group.map(toast => /*#__PURE__*/React.createElement(Toast, {
555
+ key: toast.options.id,
556
+ toast: toast,
557
+ setToasts: setToasts,
558
+ position: pos,
559
+ gap: typeof gap === 'string' ? isNaN(+gap) ? 8 : +gap : gap
560
+ }))));
561
+ })));
514
562
  }
515
563
 
516
564
  const toast = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kitzo",
3
- "version": "2.0.32",
3
+ "version": "2.0.33",
4
4
  "description": "A lightweight JavaScript UI micro-library.",
5
5
  "type": "module",
6
6
  "main": "./dist/kitzo.umd.js",