kitzo 2.0.32 → 2.0.34

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.34/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) => (
@@ -207,7 +207,7 @@ function App() {
207
207
  success: 'Data saved',
208
208
  error: 'Failed saving data',
209
209
  },
210
- { duration: 2500 },
210
+ { duration: 2500, position: 'top-center' },
211
211
  );
212
212
  }
213
213
 
@@ -221,6 +221,7 @@ function App() {
221
221
  ),
222
222
  {
223
223
  duration: 2000,
224
+ position: 'top-center',
224
225
  },
225
226
  );
226
227
  }
@@ -233,8 +234,10 @@ function App() {
233
234
  <button onClick={customToast}>Custom Toast</button>
234
235
 
235
236
  {/* Toast container must needed */}
236
- <ToastContainer position="top-center" />
237
+ <ToastContainer />
237
238
  </div>
238
239
  );
239
240
  }
240
241
  ```
242
+
243
+ > Each toast can have its own position. default position is `top-center`.
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
@@ -366,10 +366,12 @@ function Toast({
366
366
  } = options;
367
367
  const ref = useRef(null);
368
368
  useLayoutEffect(() => {
369
- const height = ref.current.getBoundingClientRect().height + gap;
370
- setToasts(prev => prev.map(t => t.id == id ? {
369
+ if (!ref.current) return;
370
+ const height = ref.current.getBoundingClientRect().height;
371
+ const totalHeight = height + gap;
372
+ setToasts(prev => prev.map(t => t.id === id ? {
371
373
  ...t,
372
- height
374
+ height: totalHeight
373
375
  } : t));
374
376
  }, []);
375
377
  const transformY = position.includes('bottom') ? `translateY(-${offset || 0}px)` : `translateY(${offset || 0}px)`;
@@ -426,10 +428,12 @@ function ToastContainer(props) {
426
428
  gap: 8
427
429
  }, props);
428
430
  const {
429
- position,
430
431
  gap
431
432
  } = props;
433
+ const position = props.position;
432
434
  const [toasts, setToasts] = useState([]);
435
+
436
+ // event listener
433
437
  useEffect(() => {
434
438
  const unsub = subscribe(toast => {
435
439
  if (toast.type === 'dismiss') {
@@ -476,19 +480,33 @@ function ToastContainer(props) {
476
480
  });
477
481
  return () => unsub();
478
482
  }, []);
479
- useEffect(() => {
480
- let offset = 0;
483
+
484
+ // measue height and offset for each toast
485
+ useLayoutEffect(() => {
486
+ const grouped = toasts.reduce((acc, t) => {
487
+ const pos = t.options.position || position || 'top-center';
488
+ (acc[pos] ||= []).push(t);
489
+ return acc;
490
+ }, {});
491
+ let hasChanged = false;
481
492
  const updated = toasts.map(toast => {
482
- const top = offset;
483
- offset += toast.height;
493
+ const pos = toast.options.position || position || 'top-center';
494
+ const group = grouped[pos];
495
+ const index = group.findIndex(t => t.id === toast.id);
496
+ const offset = group.slice(0, index).reduce((acc, t) => acc + (t.height || 0), 0);
497
+ if (offset !== toast.offset) {
498
+ hasChanged = true;
499
+ }
484
500
  return {
485
501
  ...toast,
486
- offset: top
502
+ offset
487
503
  };
488
504
  });
489
- const changed = updated.some((u, i) => u.offset != toasts[i].offset);
490
- if (changed) setToasts(updated);
505
+ if (hasChanged) {
506
+ setToasts(updated);
507
+ }
491
508
  }, [toasts]);
509
+ const positions = ['top-left', 'top-center', 'top-right', 'bottom-left', 'bottom-center', 'bottom-right'];
492
510
  return /*#__PURE__*/React.createElement("div", {
493
511
  style: {
494
512
  position: 'fixed',
@@ -496,21 +514,31 @@ function ToastContainer(props) {
496
514
  zIndex: 100000000,
497
515
  pointerEvents: 'none',
498
516
  fontFamily: 'inherit',
499
- display: 'grid',
500
- padding: '1rem',
501
517
  boxSizing: 'border-box'
502
518
  }
503
- }, /*#__PURE__*/React.createElement("div", {
504
- style: {
505
- position: 'relative'
506
- }
507
- }, toasts.map(toast => /*#__PURE__*/React.createElement(Toast, {
508
- key: toast.options.id,
509
- toast: toast,
510
- setToasts: setToasts,
511
- position: position,
512
- gap: typeof gap === 'string' ? isNaN(+gap) ? 8 : +gap : gap
513
- }))));
519
+ }, positions.map(pos => {
520
+ const group = toasts.filter(t => (t.options.position || position || 'top-center') === pos);
521
+ if (!group.length) return null;
522
+ return /*#__PURE__*/React.createElement("div", {
523
+ key: pos,
524
+ style: {
525
+ position: 'absolute',
526
+ inset: 0,
527
+ display: 'grid',
528
+ padding: '1rem'
529
+ }
530
+ }, /*#__PURE__*/React.createElement("div", {
531
+ style: {
532
+ position: 'relative'
533
+ }
534
+ }, group.map(toast => /*#__PURE__*/React.createElement(Toast, {
535
+ key: toast.options.id,
536
+ toast: toast,
537
+ setToasts: setToasts,
538
+ position: pos,
539
+ gap: typeof gap === 'string' ? isNaN(+gap) ? 8 : +gap : gap
540
+ }))));
541
+ }));
514
542
  }
515
543
 
516
544
  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.34",
4
4
  "description": "A lightweight JavaScript UI micro-library.",
5
5
  "type": "module",
6
6
  "main": "./dist/kitzo.umd.js",