@simplysm/solid 13.0.56 → 13.0.58

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.
Files changed (39) hide show
  1. package/dist/components/data/crud-detail/CrudDetail.d.ts.map +1 -1
  2. package/dist/components/data/crud-detail/CrudDetail.js +55 -42
  3. package/dist/components/data/crud-detail/CrudDetail.js.map +2 -2
  4. package/dist/components/data/crud-sheet/CrudSheet.d.ts.map +1 -1
  5. package/dist/components/data/crud-sheet/CrudSheet.js +112 -83
  6. package/dist/components/data/crud-sheet/CrudSheet.js.map +2 -2
  7. package/dist/components/data/crud-sheet/CrudSheetColumn.js +1 -1
  8. package/dist/components/data/crud-sheet/CrudSheetColumn.js.map +2 -2
  9. package/dist/components/data/crud-sheet/types.d.ts +3 -2
  10. package/dist/components/data/crud-sheet/types.d.ts.map +1 -1
  11. package/dist/components/data/sheet/DataSheet.styles.d.ts.map +1 -1
  12. package/dist/components/data/sheet/DataSheet.styles.js +3 -8
  13. package/dist/components/data/sheet/DataSheet.styles.js.map +1 -1
  14. package/dist/components/disclosure/Dialog.d.ts.map +1 -1
  15. package/dist/components/disclosure/Dialog.js +33 -23
  16. package/dist/components/disclosure/Dialog.js.map +2 -2
  17. package/dist/components/display/Icon.js +1 -1
  18. package/dist/components/display/Icon.js.map +1 -1
  19. package/dist/components/feedback/notification/NotificationBanner.js +1 -1
  20. package/dist/components/feedback/notification/NotificationBanner.js.map +1 -1
  21. package/dist/components/feedback/notification/NotificationContext.d.ts +1 -1
  22. package/dist/components/feedback/notification/NotificationContext.d.ts.map +1 -1
  23. package/dist/components/feedback/notification/NotificationContext.js.map +1 -1
  24. package/dist/components/feedback/notification/NotificationProvider.d.ts.map +1 -1
  25. package/dist/components/feedback/notification/NotificationProvider.js +8 -12
  26. package/dist/components/feedback/notification/NotificationProvider.js.map +2 -2
  27. package/docs/feedback.md +9 -8
  28. package/package.json +3 -3
  29. package/src/components/data/crud-detail/CrudDetail.tsx +45 -40
  30. package/src/components/data/crud-sheet/CrudSheet.tsx +91 -92
  31. package/src/components/data/crud-sheet/CrudSheetColumn.tsx +1 -1
  32. package/src/components/data/crud-sheet/types.ts +3 -2
  33. package/src/components/data/sheet/DataSheet.styles.ts +3 -8
  34. package/src/components/disclosure/Dialog.tsx +23 -20
  35. package/src/components/display/Icon.tsx +1 -1
  36. package/src/components/feedback/notification/NotificationBanner.tsx +1 -1
  37. package/src/components/feedback/notification/NotificationContext.ts +2 -7
  38. package/src/components/feedback/notification/NotificationProvider.tsx +8 -15
  39. package/tailwind.config.ts +1 -0
@@ -21,7 +21,7 @@ import { useNotification } from "../../feedback/notification/NotificationContext
21
21
  import { Button } from "../../form-control/Button";
22
22
  import { Icon } from "../../display/Icon";
23
23
  import { FormGroup } from "../../layout/FormGroup";
24
- import { TopbarContext, createTopbarActions } from "../../layout/topbar/TopbarContext";
24
+ import { createTopbarActions, TopbarContext } from "../../layout/topbar/TopbarContext";
25
25
  import { useDialogInstance } from "../../disclosure/DialogInstanceContext";
26
26
  import { Dialog } from "../../disclosure/Dialog";
27
27
  import { Link } from "../../display/Link";
@@ -29,6 +29,7 @@ import { createEventListener } from "@solid-primitives/event-listener";
29
29
  import clsx from "clsx";
30
30
  import {
31
31
  IconDeviceFloppy,
32
+ IconExternalLink,
32
33
  IconFileExcel,
33
34
  IconPlus,
34
35
  IconRefresh,
@@ -37,10 +38,10 @@ import {
37
38
  IconTrashOff,
38
39
  IconUpload,
39
40
  } from "@tabler/icons-solidjs";
40
- import { isCrudSheetColumnDef, CrudSheetColumn } from "./CrudSheetColumn";
41
- import { isCrudSheetFilterDef, CrudSheetFilter } from "./CrudSheetFilter";
42
- import { isCrudSheetToolsDef, CrudSheetTools } from "./CrudSheetTools";
43
- import { isCrudSheetHeaderDef, CrudSheetHeader } from "./CrudSheetHeader";
41
+ import { CrudSheetColumn, isCrudSheetColumnDef } from "./CrudSheetColumn";
42
+ import { CrudSheetFilter, isCrudSheetFilterDef } from "./CrudSheetFilter";
43
+ import { CrudSheetTools, isCrudSheetToolsDef } from "./CrudSheetTools";
44
+ import { CrudSheetHeader, isCrudSheetHeaderDef } from "./CrudSheetHeader";
44
45
  import type {
45
46
  CrudSheetColumnDef,
46
47
  CrudSheetContext,
@@ -70,6 +71,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
70
71
  "editable",
71
72
  "itemEditable",
72
73
  "itemDeletable",
74
+ "itemDeleted",
73
75
  "filterInitial",
74
76
  "items",
75
77
  "onItemsChange",
@@ -124,28 +126,27 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
124
126
 
125
127
  let formRef: HTMLFormElement | undefined;
126
128
 
127
- // -- Auto Refresh Effect --
128
129
  createEffect(() => {
129
- const currLastFilter = lastFilter();
130
- const currSorts = sorts();
131
- const currPage = page();
132
-
133
- queueMicrotask(async () => {
134
- setBusyCount((c) => c + 1);
135
- await noti.try(async () => {
136
- await refresh(currLastFilter, currSorts, currPage);
137
- }, "조회 실패");
138
- setBusyCount((c) => c - 1);
139
- setReady(true);
140
- });
130
+ void doRefresh();
141
131
  });
142
132
 
143
- async function refresh(currLastFilter: TFilter, currSorts: SortingDef[], currPage: number) {
133
+ async function doRefresh() {
134
+ setBusyCount((c) => c + 1);
135
+ try {
136
+ await refresh();
137
+ } catch (err) {
138
+ noti.error(err, "조회 실패");
139
+ }
140
+ setBusyCount((c) => c - 1);
141
+ setReady(true);
142
+ }
143
+
144
+ async function refresh() {
144
145
  const usePagination = local.itemsPerPage != null;
145
146
  const result: SearchResult<TItem> = await local.search(
146
- currLastFilter,
147
- usePagination ? currPage : 0,
148
- currSorts,
147
+ lastFilter(),
148
+ usePagination ? page() : 0,
149
+ sorts(),
149
150
  );
150
151
  setItems(reconcile(result.items));
151
152
  originalItems = objClone(result.items);
@@ -210,17 +211,14 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
210
211
  return;
211
212
  }
212
213
 
213
- const currLastFilter = lastFilter();
214
- const currSorts = sorts();
215
- const currPage = page();
216
-
217
214
  setBusyCount((c) => c + 1);
218
- // eslint-disable-next-line solid/reactivity -- noti.try 내부에서 비동기 refresh 호출
219
- await noti.try(async () => {
220
- await local.inlineEdit!.submit(diffs);
215
+ try {
216
+ await local.inlineEdit.submit(diffs);
221
217
  noti.success("저장 완료", "저장되었습니다.");
222
- await refresh(currLastFilter, currSorts, currPage);
223
- }, "저장 실패");
218
+ await refresh();
219
+ } catch (err) {
220
+ noti.error(err, "저장 실패");
221
+ }
224
222
  setBusyCount((c) => c - 1);
225
223
  }
226
224
 
@@ -236,10 +234,11 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
236
234
  if (!result) return;
237
235
 
238
236
  setBusyCount((c) => c + 1);
239
- // eslint-disable-next-line solid/reactivity -- noti.try 내부에서 비동기 refresh 호출
240
- await noti.try(async () => {
241
- await refresh(lastFilter(), sorts(), page());
242
- }, "조회 실패");
237
+ try {
238
+ await refresh();
239
+ } catch (err) {
240
+ noti.error(err, "조회 실패");
241
+ }
243
242
  setBusyCount((c) => c - 1);
244
243
  }
245
244
 
@@ -249,11 +248,12 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
249
248
  if (!result) return;
250
249
 
251
250
  setBusyCount((c) => c + 1);
252
- // eslint-disable-next-line solid/reactivity -- noti.try 내부에서 비동기 refresh 호출
253
- await noti.try(async () => {
254
- await refresh(lastFilter(), sorts(), page());
251
+ try {
252
+ await refresh();
255
253
  noti.success("삭제 완료", "삭제되었습니다.");
256
- }, "삭제 실패");
254
+ } catch (err) {
255
+ noti.error(err, "삭제 실패");
256
+ }
257
257
  setBusyCount((c) => c - 1);
258
258
  }
259
259
 
@@ -262,11 +262,12 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
262
262
  if (!local.excel) return;
263
263
 
264
264
  setBusyCount((c) => c + 1);
265
- // eslint-disable-next-line solid/reactivity -- noti.try 내부에서 비동기 호출
266
- await noti.try(async () => {
265
+ try {
267
266
  const result = await local.search(lastFilter(), 0, sorts());
268
- await local.excel!.download(result.items);
269
- }, "엑셀 다운로드 실패");
267
+ await local.excel.download(result.items);
268
+ } catch (err) {
269
+ noti.error(err, "엑셀 다운로드 실패");
270
+ }
270
271
  setBusyCount((c) => c - 1);
271
272
  }
272
273
 
@@ -281,12 +282,13 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
281
282
  if (file == null) return;
282
283
 
283
284
  setBusyCount((c) => c + 1);
284
- // eslint-disable-next-line solid/reactivity -- noti.try 내부에서 비동기 호출
285
- await noti.try(async () => {
285
+ try {
286
286
  await local.excel!.upload!(file);
287
287
  noti.success("완료", "엑셀 업로드가 완료되었습니다.");
288
- await refresh(lastFilter(), sorts(), page());
289
- }, "엑셀 업로드 실패");
288
+ await refresh();
289
+ } catch (err) {
290
+ noti.error(err, "엑셀 업로드 실패");
291
+ }
290
292
  setBusyCount((c) => c - 1);
291
293
  };
292
294
  input.click();
@@ -364,6 +366,7 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
364
366
 
365
367
  // -- Render --
366
368
  const deleteProp = () => local.inlineEdit?.deleteProp;
369
+ const isItemDeleted = (item: TItem) => local.itemDeleted?.(item) ?? false;
367
370
 
368
371
  return (
369
372
  <>
@@ -385,17 +388,19 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
385
388
  class={clsx("flex h-full flex-col", local.class)}
386
389
  >
387
390
  {/* Control mode: inline save/refresh bar */}
388
- <Show when={!isModal && !topbarCtx && canEdit() && local.inlineEdit}>
391
+ <Show when={!isModal && !topbarCtx}>
389
392
  <div class="flex gap-2 p-2 pb-0">
390
- <Button
391
- size="sm"
392
- theme="primary"
393
- variant="ghost"
394
- onClick={() => formRef?.requestSubmit()}
395
- >
396
- <Icon icon={IconDeviceFloppy} class="mr-1" />
397
- 저장
398
- </Button>
393
+ <Show when={canEdit() && local.inlineEdit}>
394
+ <Button
395
+ size="sm"
396
+ theme="primary"
397
+ variant="ghost"
398
+ onClick={() => formRef?.requestSubmit()}
399
+ >
400
+ <Icon icon={IconDeviceFloppy} class="mr-1" />
401
+ 저장
402
+ </Button>
403
+ </Show>
399
404
  <Button size="sm" theme="info" variant="ghost" onClick={handleRefresh}>
400
405
  <Icon icon={IconRefresh} class="mr-1" />
401
406
  새로고침
@@ -506,43 +511,34 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
506
511
  selectedItems={selectedItems()}
507
512
  onSelectedItemsChange={setSelectedItems}
508
513
  autoSelect={isSelectMode() && local.selectMode === "single" ? "click" : undefined}
509
- cellClass={(item, _colKey) => {
510
- const dp = deleteProp();
511
- if (dp != null && Boolean((item as Record<string, unknown>)[dp])) {
514
+ cellClass={(item) => {
515
+ if (isItemDeleted(item)) {
512
516
  return clsx("line-through");
513
517
  }
514
518
  return undefined;
515
519
  }}
516
520
  >
517
- {/* Auto delete column */}
518
- <Show when={deleteProp() != null && canEdit() ? deleteProp() : undefined}>
519
- {(dp) => (
520
- <DataSheetColumn<TItem>
521
- key="__delete"
522
- header=""
523
- fixed
524
- sortable={false}
525
- resizable={false}
526
- >
527
- {(dsCtx) => (
528
- <div class="flex items-center justify-center px-1 py-0.5">
529
- <Link
530
- theme="danger"
531
- disabled={!(local.itemDeletable?.(dsCtx.item) ?? true)}
532
- onClick={() => handleToggleDelete(dsCtx.item, dsCtx.index)}
533
- >
534
- <Icon
535
- icon={
536
- Boolean((dsCtx.item as Record<string, unknown>)[dp()])
537
- ? IconTrashOff
538
- : IconTrash
539
- }
540
- />
541
- </Link>
542
- </div>
543
- )}
544
- </DataSheetColumn>
545
- )}
521
+ {/* Auto delete column (inline edit only) */}
522
+ <Show when={deleteProp() != null && canEdit()}>
523
+ <DataSheetColumn<TItem>
524
+ key="__delete"
525
+ header=""
526
+ fixed
527
+ sortable={false}
528
+ resizable={false}
529
+ >
530
+ {(dsCtx) => (
531
+ <div class="flex items-center justify-center px-1 py-0.5">
532
+ <Link
533
+ theme="danger"
534
+ disabled={!(local.itemDeletable?.(dsCtx.item) ?? true)}
535
+ onClick={() => handleToggleDelete(dsCtx.item, dsCtx.index)}
536
+ >
537
+ <Icon icon={isItemDeleted(dsCtx.item) ? IconTrashOff : IconTrash} />
538
+ </Link>
539
+ </div>
540
+ )}
541
+ </DataSheetColumn>
546
542
  </Show>
547
543
 
548
544
  {/* User-defined columns -- map CrudSheetColumn to DataSheetColumn */}
@@ -574,20 +570,23 @@ const CrudSheetBase = <TItem, TFilter extends Record<string, any>>(
574
570
  // modalEdit editable column -- wrap with edit link
575
571
  if (
576
572
  local.modalEdit &&
577
- col.editable &&
573
+ col.editTrigger &&
578
574
  canEdit() &&
579
575
  (local.itemEditable?.(dsCtx.item) ?? true)
580
576
  ) {
581
577
  return (
582
578
  <Link
583
- class="flex w-full"
579
+ class={clsx("flex", "gap-1")}
584
580
  onClick={(e) => {
585
581
  e.preventDefault();
586
582
  e.stopPropagation();
587
583
  void handleEditItem(dsCtx.item);
588
584
  }}
589
585
  >
590
- {col.cell(crudCtx)}
586
+ <div class={"p-1"}>
587
+ <Icon icon={IconExternalLink} />
588
+ </div>
589
+ <div class={"flex-1"}>{col.cell(crudCtx)}</div>
591
590
  </Link>
592
591
  );
593
592
  }
@@ -28,7 +28,7 @@ export function CrudSheetColumn<TItem>(props: CrudSheetColumnProps<TItem>): JSX.
28
28
  width: props.width,
29
29
  sortable: props.sortable ?? true,
30
30
  resizable: props.resizable ?? true,
31
- editable: props.editable ?? false,
31
+ editTrigger: props.editTrigger ?? false,
32
32
  } as unknown as JSX.Element;
33
33
  }
34
34
  /* eslint-enable solid/reactivity */
@@ -80,6 +80,7 @@ interface CrudSheetBaseProps<TItem, TFilter extends Record<string, any>> {
80
80
  editable?: boolean;
81
81
  itemEditable?: (item: TItem) => boolean;
82
82
  itemDeletable?: (item: TItem) => boolean;
83
+ itemDeleted?: (item: TItem) => boolean;
83
84
  filterInitial?: TFilter;
84
85
  items?: TItem[];
85
86
  onItemsChange?: (items: TItem[]) => void;
@@ -108,12 +109,12 @@ export interface CrudSheetColumnDef<TItem> {
108
109
  class?: string;
109
110
  sortable: boolean;
110
111
  resizable: boolean;
111
- editable: boolean;
112
+ editTrigger: boolean;
112
113
  cell: (ctx: CrudSheetCellContext<TItem>) => JSX.Element;
113
114
  }
114
115
 
115
116
  export interface CrudSheetColumnProps<TItem> extends Omit<DataSheetColumnProps<TItem>, "children"> {
116
- editable?: boolean;
117
+ editTrigger?: boolean;
117
118
  children: (ctx: CrudSheetCellContext<TItem>) => JSX.Element;
118
119
  }
119
120
 
@@ -3,7 +3,8 @@ import { borderDefault, borderSubtle } from "../../../styles/tokens.styles";
3
3
 
4
4
  export const dataSheetContainerClass = clsx(
5
5
  "relative",
6
- "bg-white dark:bg-base-950",
6
+ // "bg-white dark:bg-base-950",
7
+ "bg-base-100 dark:bg-base-900",
7
8
  "overflow-auto",
8
9
  );
9
10
 
@@ -50,13 +51,7 @@ export const sortableThClass = clsx("cursor-pointer", "hover:underline");
50
51
  export const sortIconClass = clsx("px-1 py-0.5", "bg-base-100 dark:bg-base-900");
51
52
 
52
53
  // 상단 툴바 (설정 버튼 + 페이지네이션)
53
- export const toolbarClass = clsx(
54
- "flex items-center gap-2",
55
- "px-2 py-1",
56
- "bg-base-50 dark:bg-base-900",
57
- "border-b",
58
- borderDefault,
59
- );
54
+ export const toolbarClass = clsx("flex items-center gap-2", "px-2 py-1", "border-b", borderDefault);
60
55
 
61
56
  // 고정 컬럼 기본 (sticky)
62
57
  export const fixedClass = "sticky";
@@ -1,15 +1,15 @@
1
1
  import {
2
- type JSX,
3
- type ParentComponent,
4
2
  createContext,
5
3
  createEffect,
4
+ createSignal,
6
5
  createUniqueId,
6
+ For,
7
+ type JSX,
7
8
  onCleanup,
9
+ type ParentComponent,
8
10
  Show,
9
11
  splitProps,
10
- For,
11
12
  useContext,
12
- createSignal,
13
13
  } from "solid-js";
14
14
  import { Portal } from "solid-js/web";
15
15
  import clsx from "clsx";
@@ -22,7 +22,8 @@ import { mergeStyles } from "../../helpers/mergeStyles";
22
22
  import { Icon } from "../display/Icon";
23
23
  import { borderSubtle } from "../../styles/tokens.styles";
24
24
  import { DialogDefaultsContext } from "./DialogContext";
25
- import { registerDialog, unregisterDialog, bringToFront } from "./dialogZIndex";
25
+ import { bringToFront, registerDialog, unregisterDialog } from "./dialogZIndex";
26
+ import { Button } from "../form-control/Button";
26
27
 
27
28
  type SlotAccessor = (() => JSX.Element) | undefined;
28
29
 
@@ -212,11 +213,19 @@ export const Dialog: DialogComponent = (props) => {
212
213
  local.onCloseComplete?.();
213
214
  };
214
215
 
215
- // open 변경 시 closeCompleteEmitted 초기화
216
+ // open 변경 시 closeCompleteEmitted 초기화 + fallback unmount 감지
217
+ let wasMounted = false;
216
218
  createEffect(() => {
217
219
  if (open()) {
218
220
  closeCompleteEmitted = false;
219
221
  }
222
+ if (mounted()) {
223
+ wasMounted = true;
224
+ } else if (wasMounted) {
225
+ // fallback timer가 transitionend보다 먼저 실행되어 DOM이 제거된 경우,
226
+ // onCloseComplete가 호출되지 않는 문제 방지
227
+ emitCloseComplete();
228
+ }
220
229
  });
221
230
 
222
231
  // dialog ref
@@ -477,7 +486,8 @@ export const Dialog: DialogComponent = (props) => {
477
486
  );
478
487
 
479
488
  // 헤더 클래스
480
- const headerClass = () => clsx("flex items-center", "select-none", "border-b", borderSubtle);
489
+ const headerClass = () =>
490
+ clsx("flex items-center gap-2", "px-3 py-1", "select-none", "border-b", borderSubtle);
481
491
 
482
492
  return (
483
493
  <Show when={mounted()}>
@@ -516,26 +526,19 @@ export const Dialog: DialogComponent = (props) => {
516
526
  }
517
527
  onPointerDown={handleHeaderPointerDown}
518
528
  >
519
- <h5 id={headerId} class={clsx("flex-1", "px-4 py-2", "text-sm font-bold")}>
529
+ <h5 id={headerId} class={clsx("flex-1 font-bold")}>
520
530
  {header()!()}
521
531
  </h5>
522
532
  <Show when={action()}>{action()!()}</Show>
523
533
  <Show when={local.closable ?? true}>
524
- <button
534
+ <Button
525
535
  data-modal-close
526
- type="button"
527
- class={clsx(
528
- "inline-flex items-center justify-center",
529
- "px-3 py-2",
530
- "text-base-400 dark:text-base-500",
531
- "hover:text-base-600 dark:hover:text-base-300",
532
- "cursor-pointer",
533
- "transition-colors",
534
- )}
536
+ size={"sm"}
537
+ variant={"ghost"}
535
538
  onClick={handleCloseClick}
536
539
  >
537
- <Icon icon={IconX} size="1.25em" />
538
- </button>
540
+ <Icon icon={IconX} />
541
+ </Button>
539
542
  </Show>
540
543
  </div>
541
544
  </Show>
@@ -16,7 +16,7 @@ export const Icon: Component<IconProps> = (props) => {
16
16
  component={local.icon}
17
17
  size={local.size ?? "1.25em"}
18
18
  {...rest}
19
- class={clsx("inline", rest.class)}
19
+ class={clsx("inline", "[vertical-align:-0.25em]", rest.class)}
20
20
  />
21
21
  );
22
22
  };
@@ -10,7 +10,7 @@ const baseClass = clsx(
10
10
  "fixed",
11
11
  "top-8",
12
12
  "right-4",
13
- "z-50",
13
+ "z-notification",
14
14
  "flex",
15
15
  "items-start",
16
16
  "gap-4",
@@ -1,4 +1,4 @@
1
- import { createContext, useContext, type Accessor } from "solid-js";
1
+ import { type Accessor, createContext, useContext } from "solid-js";
2
2
 
3
3
  /** 알림 테마 */
4
4
  export type NotificationTheme = "info" | "success" | "warning" | "danger";
@@ -59,12 +59,7 @@ export interface NotificationContextValue {
59
59
  success: (title: string, message?: string, options?: NotificationOptions) => string;
60
60
  warning: (title: string, message?: string, options?: NotificationOptions) => string;
61
61
  danger: (title: string, message?: string, options?: NotificationOptions) => string;
62
-
63
- // 에러 처리 (danger 알림 + 로깅)
64
- try: <TResult>(
65
- fn: () => Promise<TResult> | TResult,
66
- header?: string,
67
- ) => Promise<TResult | undefined>;
62
+ error: (err?: any, header?: string) => void;
68
63
 
69
64
  // 알림 수정
70
65
  update: (
@@ -1,4 +1,4 @@
1
- import { type ParentComponent, createSignal, createMemo, Show } from "solid-js";
1
+ import { createMemo, createSignal, type ParentComponent, Show } from "solid-js";
2
2
  import {
3
3
  NotificationContext,
4
4
  type NotificationContextValue,
@@ -79,20 +79,13 @@ export const NotificationProvider: ParentComponent = (props) => {
79
79
  return addNotification("danger", title, message, options);
80
80
  };
81
81
 
82
- const tryFn = async <TResult,>(
83
- fn: () => Promise<TResult> | TResult,
84
- header?: string,
85
- ): Promise<TResult | undefined> => {
86
- try {
87
- return await fn();
88
- } catch (err) {
89
- if (err instanceof Error) {
90
- danger(header ?? err.message, header != null ? err.message : undefined);
91
- logger.error(err.stack ?? err.message);
92
- return undefined;
93
- }
94
- throw err;
82
+ const error = (err?: any, header?: string): void => {
83
+ if (err instanceof Error) {
84
+ danger(header ?? err.message, header != null ? err.message : undefined);
85
+ logger.error(err.stack ?? err.message);
86
+ return;
95
87
  }
88
+ throw err;
96
89
  };
97
90
 
98
91
  const update = (
@@ -151,7 +144,7 @@ export const NotificationProvider: ParentComponent = (props) => {
151
144
  success,
152
145
  warning,
153
146
  danger,
154
- try: tryFn,
147
+ error,
155
148
  update,
156
149
  remove,
157
150
  markAsRead,
@@ -52,6 +52,7 @@ export default {
52
52
  "dropdown": "1000",
53
53
  "modal-backdrop": "1999",
54
54
  "modal": "2000",
55
+ "notification": "3000",
55
56
  },
56
57
  },
57
58
  },