@rkosafo/cai.components 0.0.66 → 0.0.67

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 (37) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +2 -0
  3. package/dist/keycloak/keycloakService.d.ts +5 -1
  4. package/dist/keycloak/keycloakService.js +1 -1
  5. package/dist/layout/mailing/MailPaginator.svelte +36 -0
  6. package/dist/layout/mailing/MailPaginator.svelte.d.ts +4 -0
  7. package/dist/layout/mailing/MailSidebar.svelte +39 -0
  8. package/dist/layout/mailing/MailSidebar.svelte.d.ts +4 -0
  9. package/dist/layout/mailing/MailToolBar.svelte +174 -0
  10. package/dist/layout/mailing/MailToolBar.svelte.d.ts +4 -0
  11. package/dist/layout/mailing/MailingHeader.svelte +5 -0
  12. package/dist/layout/mailing/MailingHeader.svelte.d.ts +4 -0
  13. package/dist/layout/mailing/MailingMessageCard.svelte +106 -0
  14. package/dist/layout/mailing/MailingMessageCard.svelte.d.ts +4 -0
  15. package/dist/layout/mailing/MailingMessageViewer.svelte +63 -0
  16. package/dist/layout/mailing/MailingMessageViewer.svelte.d.ts +4 -0
  17. package/dist/layout/mailing/MailingModule.svelte +415 -0
  18. package/dist/layout/mailing/MailingModule.svelte.d.ts +4 -0
  19. package/dist/layout/mailing/index.d.ts +7 -0
  20. package/dist/layout/mailing/index.js +7 -0
  21. package/dist/layout/mailing/types.d.ts +126 -0
  22. package/dist/layout/mailing/types.js +1 -0
  23. package/dist/themes/themes.d.ts +1 -0
  24. package/dist/themes/themes.js +1 -0
  25. package/dist/types/index.d.ts +4 -0
  26. package/dist/ui/pageLoader/PageLoader.svelte +6 -2
  27. package/dist/ui/toast/Toast.svelte +1 -1
  28. package/dist/ui/toast/Toast.svelte.d.ts +1 -1
  29. package/dist/ui/tooltip/Tooltip.svelte +51 -0
  30. package/dist/ui/tooltip/Tooltip.svelte.d.ts +17 -0
  31. package/dist/ui/tooltip/index.d.ts +2 -0
  32. package/dist/ui/tooltip/index.js +2 -0
  33. package/dist/ui/tooltip/theme.d.ts +90 -0
  34. package/dist/ui/tooltip/theme.js +45 -0
  35. package/dist/utils/paginate.svelte.d.ts +1 -0
  36. package/dist/utils/paginate.svelte.js +4 -0
  37. package/package.json +1 -1
@@ -0,0 +1,415 @@
1
+ <script lang="ts">
2
+ import { PageLoader } from '../../ui/pageLoader/index.js';
3
+ import { scale, slide } from 'svelte/transition';
4
+ import {
5
+ MailSidebar,
6
+ MailToolBar,
7
+ type MailingModuleProps,
8
+ type MailMenu,
9
+ type MailingMessage,
10
+ type MailMarkReadToggleType,
11
+ type MailFavariteToggleType,
12
+ type MailPageInfo
13
+ } from './index.js';
14
+ import MailingMessageCard from './MailingMessageCard.svelte';
15
+ import { toast, type CrudResult, type TableFilter } from '../../index.js';
16
+ import { PageInfo } from '../../utils/paginate.svelte.js';
17
+ import AlertDialog from '../../ui/alertDialog/AlertDialog.svelte';
18
+ import MailingMessageViewer from './MailingMessageViewer.svelte';
19
+
20
+ let {
21
+ showSidePanel = true,
22
+ showPagination = true,
23
+ showComposeButton = true,
24
+ showSearch = true,
25
+ customFilterComponent,
26
+ showArchiveButton = true,
27
+ showDeleteButton = true,
28
+ showMarkReadButton = true,
29
+ showFavoriteButton = true,
30
+ showMarkAsSpamButton = true,
31
+ readInbox = $bindable((skip?: number, take?: number, filter?: TableFilter<any>) => {
32
+ return null;
33
+ }),
34
+ readOutbox = $bindable((skip?: number, take?: number, filter?: TableFilter<any>) => {
35
+ return null;
36
+ }),
37
+ deleteEntry = async (id: string | number) => {
38
+ return { success: false, data: null, error: null } as any;
39
+ },
40
+ toggleArchieve = async (id: string | number) => {
41
+ return { success: false, data: null, error: null } as any;
42
+ },
43
+ toggleAsRead = async (id: string | number) => {
44
+ return { success: false, data: null, error: null } as any;
45
+ },
46
+ toggleFavourite = async (id: string | number) => {
47
+ return { success: false, data: null, error: null } as any;
48
+ },
49
+ toggleSpam = async (id: string | number) => {
50
+ return { success: false, data: null, error: null } as any;
51
+ },
52
+ toggelImportant = async (id: string | number) => {
53
+ return { success: false, data: null, error: null } as any;
54
+ },
55
+ readAMessage = async (id: string | number) => {
56
+ return { success: false, data: null, error: null } as any;
57
+ }
58
+ }: MailingModuleProps = $props();
59
+
60
+ type ActiveBox = 'inbox' | 'outbox';
61
+
62
+ let activeBox = $state<ActiveBox>('inbox');
63
+ let pageInfo = new PageInfo();
64
+ let menutItems = $state([
65
+ { icon: 'bx:bxs-inbox', title: 'Inbox', count: 3, path: '' },
66
+ { icon: 'bx:bxs-send', title: 'Sent', count: 0, path: '' }
67
+ ]);
68
+ let openDeleteAlert = $state(false);
69
+ let busy = $state(true);
70
+ let messages = $state<MailingMessage[]>([]);
71
+ let pageNumber = $derived(pageInfo.currentPage);
72
+ let query = $state('');
73
+ let selectedMessages = $state<number[]>([]);
74
+ let messageSelected = $state<number>(0);
75
+
76
+ function toggleSideBar(val: MailMenu) {
77
+ const { title } = val;
78
+ if (title === 'Inbox') activeBox = 'inbox';
79
+ else activeBox = 'outbox';
80
+ }
81
+
82
+ function setActiveMenu(val: MailMenu): boolean {
83
+ if (activeBox === 'inbox' && val.title === 'Inbox') return true;
84
+ else if (activeBox === 'outbox' && val.title === 'Sent') return true;
85
+ else return false;
86
+ }
87
+
88
+ async function fetchData(page: number, params: TableFilter, activeBox: ActiveBox = 'inbox') {
89
+ try {
90
+ let currentPage = 0;
91
+ if (params.search) {
92
+ pageInfo.setCurrentPage(1);
93
+ currentPage = pageInfo.currentPage;
94
+ } else {
95
+ currentPage = page || pageInfo.currentPage;
96
+ }
97
+ let newParams: any = {
98
+ page: currentPage,
99
+ pageSize: pageInfo.pageSize,
100
+ search: params.search ?? '',
101
+ filter: params.filter ?? {},
102
+ order: params.order ?? []
103
+ };
104
+ let read = activeBox === activeBox ? readInbox : readOutbox;
105
+ const ret = await read(newParams.page, newParams.pageSize, {
106
+ ...params,
107
+ filter: {},
108
+ search: newParams.search ?? ''
109
+ });
110
+ if (!ret?.success) {
111
+ // showError(ret?.message || 'Failed to load data');
112
+ toast.error(ret?.message || 'Failed to load data');
113
+ return true;
114
+ }
115
+ const xs = ret.data;
116
+ // console.log({ xs });
117
+ pageInfo.totalItems = xs.totalCount;
118
+ pageInfo.setHasNextPage(xs.pageInfo.hasNextPage);
119
+ pageInfo.setHasPrevPage(xs.pageInfo.hasPreviousPage);
120
+ // tableData = xs.items;
121
+ messages = xs.items.map((a) => ({ ...a, isChecked: false }));
122
+ } catch (e: any) {
123
+ toast.error(e.message || e);
124
+ } finally {
125
+ busy = false;
126
+ }
127
+ }
128
+
129
+ function handleRefreshClick() {
130
+ busy = true;
131
+ fetchData(pageNumber, { search: query }, activeBox);
132
+ }
133
+
134
+ async function handleArchiveClick() {
135
+ if (selectedMessages.length === 0) return;
136
+
137
+ toast.promise(
138
+ (async () => {
139
+ const results = [];
140
+
141
+ for (const msg of selectedMessages) {
142
+ const res = await toggleArchieve(msg);
143
+ results.push(res);
144
+ }
145
+ selectedMessages = [];
146
+ fetchData(pageNumber, { search: query }, activeBox);
147
+
148
+ return {
149
+ message: `${results.length} message(s) archived successfully`,
150
+ results
151
+ };
152
+ })(),
153
+ {
154
+ loading: `Archiving message(s)...`,
155
+ success: (data: any) => data?.message,
156
+ error: (err: any) => err?.message || 'Failed to archive messages'
157
+ }
158
+ );
159
+ }
160
+
161
+ async function handleMarkAsSpam() {
162
+ if (selectedMessages.length === 0) return;
163
+
164
+ toast.promise(
165
+ (async () => {
166
+ const results = [];
167
+
168
+ for (const msg of selectedMessages) {
169
+ const res = await toggleSpam(msg);
170
+ results.push(res);
171
+ }
172
+ selectedMessages = [];
173
+ fetchData(pageNumber, { search: query }, activeBox);
174
+
175
+ return {
176
+ message: `${results.length} message(s) marked as spam successfully`,
177
+ results
178
+ };
179
+ })(),
180
+ {
181
+ loading: `Marking message(s) as spam...`,
182
+ success: (data: any) => data?.message,
183
+ error: (err: any) => err?.message || 'Failed to archive messages'
184
+ }
185
+ );
186
+ }
187
+
188
+ async function handleMarkAsRead(val: MailMarkReadToggleType) {
189
+ if (selectedMessages.length === 0) return;
190
+
191
+ toast.promise(
192
+ (async () => {
193
+ const results = [];
194
+
195
+ for (const msg of selectedMessages) {
196
+ const res = await toggleAsRead(msg);
197
+ results.push(res);
198
+ }
199
+ selectedMessages = [];
200
+ fetchData(pageNumber, { search: query }, activeBox);
201
+
202
+ return {
203
+ message: `${results.length} message(s) marked as ${val === 'read' ? 'read' : 'unread'} successfully`,
204
+ results
205
+ };
206
+ })(),
207
+ {
208
+ loading: `Marking message(s) as ${val === 'read' ? 'read' : 'unread'}...`,
209
+ success: (data: any) => data?.message,
210
+ error: (err: any) =>
211
+ err?.message || `Failed to ${val === 'read' ? 'read' : 'unread'} messages`
212
+ }
213
+ );
214
+ }
215
+
216
+ async function handleMarkAsFavorite(val: MailFavariteToggleType) {
217
+ if (selectedMessages.length === 0) return;
218
+
219
+ toast.promise(
220
+ (async () => {
221
+ const results = [];
222
+
223
+ for (const msg of selectedMessages) {
224
+ const res = await toggleFavourite(msg);
225
+ results.push(res);
226
+ }
227
+ selectedMessages = [];
228
+ fetchData(pageNumber, { search: query }, activeBox);
229
+
230
+ return {
231
+ message: `${results.length} message(s) marked as ${val === 'favorite' ? 'favorite' : 'unfavorite'} successfully`,
232
+ results
233
+ };
234
+ })(),
235
+ {
236
+ loading: `Marking message(s) as ${val === 'favorite' ? 'favorite' : 'unfavorite'}...`,
237
+ success: (data: any) => data?.message,
238
+ error: (err: any) =>
239
+ err?.message || `Failed to ${val === 'favorite' ? 'favorite' : 'unfavorite'} messages`
240
+ }
241
+ );
242
+ }
243
+
244
+ async function handleMarkAsImportant(val: 'isImportant' | 'notImportant') {
245
+ if (selectedMessages.length === 0) return;
246
+
247
+ toast.promise(
248
+ (async () => {
249
+ const results = [];
250
+
251
+ for (const msg of selectedMessages) {
252
+ const res = await toggelImportant(msg);
253
+ results.push(res);
254
+ }
255
+ selectedMessages = [];
256
+ fetchData(pageNumber, { search: query }, activeBox);
257
+
258
+ return {
259
+ message: `${results.length} message(s) marked as ${val === 'isImportant' ? 'important' : 'not important'} successfully`,
260
+ results
261
+ };
262
+ })(),
263
+ {
264
+ loading: `Marking message(s) as ${val === 'isImportant' ? 'important' : 'not important'}...`,
265
+ success: (data: any) => data?.message,
266
+ error: (err: any) =>
267
+ err?.message ||
268
+ `Failed to ${val === 'isImportant' ? 'important' : 'not important'} messages`
269
+ }
270
+ );
271
+ }
272
+
273
+ async function handleDeleteMessages() {
274
+ if (selectedMessages.length === 0) return;
275
+
276
+ toast.promise(
277
+ (async () => {
278
+ const results = [];
279
+
280
+ for (const msg of selectedMessages) {
281
+ const res = await deleteEntry(msg);
282
+ results.push(res);
283
+ }
284
+
285
+ openDeleteAlert = false;
286
+ selectedMessages = [];
287
+ fetchData(pageNumber, { search: query }, activeBox);
288
+
289
+ return {
290
+ message: `${results.length} message(s) deleted successfully`,
291
+ results
292
+ };
293
+ })(),
294
+ {
295
+ loading: `Deleting message(s)...`,
296
+ success: (data: any) => data?.message,
297
+ error: (err: any) => err?.message || 'Failed to delete messages'
298
+ }
299
+ );
300
+ }
301
+
302
+ function handleItemChecked({ checked, id }: any) {
303
+ if (checked) {
304
+ selectedMessages = [...selectedMessages, id];
305
+ } else {
306
+ selectedMessages = selectedMessages.filter((a) => a !== id);
307
+ }
308
+ }
309
+
310
+ function handleMessageSelected(id: number) {
311
+ messageSelected = id;
312
+ selectedMessages = [id];
313
+ }
314
+
315
+ function updatePageInfo(val: MailPageInfo) {
316
+ console.log({ val });
317
+ pageInfo.totalItems = 1;
318
+ pageInfo.setHasNextPage(val.hasNextPage);
319
+ pageInfo.setHasPrevPage(val.hasPreviousPage);
320
+ pageInfo.setTotalPages(1);
321
+ pageInfo.setPageSize(1);
322
+ }
323
+
324
+ $effect(() => {
325
+ fetchData(pageNumber, { search: query }, activeBox);
326
+ });
327
+ </script>
328
+
329
+ <div class="h-full w-full">
330
+ <div class="flex h-full w-full gap-2">
331
+ <div class:hidden={!showSidePanel} class="loginbox h-full w-20 rounded-md bg-white">
332
+ <MailSidebar onClick={toggleSideBar} menus={menutItems} {setActiveMenu} />
333
+ </div>
334
+ <div class="flex w-full flex-grow flex-col gap-1">
335
+ <div class="loginbox h-14 rounded bg-white px-4">
336
+ <MailToolBar
337
+ isFavoriteActive={false}
338
+ isReadActive={false}
339
+ showBackButton={Boolean(messageSelected)}
340
+ {showPagination}
341
+ {showComposeButton}
342
+ {showSearch}
343
+ {showArchiveButton}
344
+ {showDeleteButton}
345
+ {showMarkReadButton}
346
+ {showFavoriteButton}
347
+ {showMarkAsSpamButton}
348
+ {customFilterComponent}
349
+ onRefreshClick={handleRefreshClick}
350
+ onArchiveClick={handleArchiveClick}
351
+ onMarkAsSpamClick={handleMarkAsSpam}
352
+ onToggleMarkReadClick={handleMarkAsRead}
353
+ onToggleFavoriteClick={handleMarkAsFavorite}
354
+ onBackClick={() => {
355
+ messageSelected = 0;
356
+ selectedMessages = [];
357
+ }}
358
+ onDeleteClick={() => {
359
+ if (selectedMessages.length === 0) return;
360
+ openDeleteAlert = true;
361
+ }}
362
+ selectedMails={selectedMessages}
363
+ pageInfo={{
364
+ currentPage: pageInfo.currentPage,
365
+ pageSize: pageInfo.pageSize,
366
+ totalCount: pageInfo.totalItems,
367
+ hasNextPage: pageInfo.hasNextPage,
368
+ hasPreviousPage: pageInfo.hasPrevPage
369
+ }}
370
+ />
371
+ </div>
372
+
373
+ <div class="loginbox h-full w-full flex-grow rounded bg-gray-100 p-2">
374
+ {#if busy}
375
+ <PageLoader size={50} />
376
+ {:else if messageSelected}
377
+ <MailingMessageViewer
378
+ recordId={messageSelected}
379
+ readMessage={readAMessage}
380
+ {updatePageInfo}
381
+ />
382
+ {:else if messages.length}
383
+ <div class="custom-scrollbar h-full w-full overflow-auto" in:slide>
384
+ {#each messages as message}
385
+ <MailingMessageCard
386
+ {...message}
387
+ onItemChecked={handleItemChecked}
388
+ toggleFavorited={() => {
389
+ selectedMessages = [message.id];
390
+ handleMarkAsFavorite(message.isStared ? 'unfavorite' : 'favorite');
391
+ }}
392
+ toggelImportant={() => {
393
+ selectedMessages = [message.id];
394
+ handleMarkAsImportant(message.isImportant ? 'notImportant' : 'isImportant');
395
+ }}
396
+ onItemSelected={handleMessageSelected}
397
+ />
398
+ {/each}
399
+ </div>
400
+ {:else}
401
+ <div class="grid h-full w-full items-center justify-center p-20" in:scale>
402
+ <div class="rounded-[5px] bg-yellow-300 px-10 py-5 text-center">No Records Found</div>
403
+ </div>
404
+ {/if}
405
+ </div>
406
+ </div>
407
+ </div>
408
+ </div>
409
+
410
+ <AlertDialog
411
+ open={openDeleteAlert}
412
+ message={`Are you sure you want to delete ${selectedMessages?.length > 1 ? 'these messages' : 'this message'}`}
413
+ onCancel={() => (openDeleteAlert = false)}
414
+ onYes={handleDeleteMessages}
415
+ />
@@ -0,0 +1,4 @@
1
+ import { type MailingModuleProps } from './index.js';
2
+ declare const MailingModule: import("svelte").Component<MailingModuleProps, {}, "readInbox" | "readOutbox">;
3
+ type MailingModule = ReturnType<typeof MailingModule>;
4
+ export default MailingModule;
@@ -0,0 +1,7 @@
1
+ export * from './types.js';
2
+ export { default as MailPaginator } from './MailPaginator.svelte';
3
+ export { default as MailSidebar } from './MailSidebar.svelte';
4
+ export { default as MailToolBar } from './MailToolBar.svelte';
5
+ export { default as MailingModule } from './MailingModule.svelte';
6
+ export { default as MailingHeader } from './MailingHeader.svelte';
7
+ export { default as MailingMessageViewer } from './MailingMessageViewer.svelte';
@@ -0,0 +1,7 @@
1
+ export * from './types.js';
2
+ export { default as MailPaginator } from './MailPaginator.svelte';
3
+ export { default as MailSidebar } from './MailSidebar.svelte';
4
+ export { default as MailToolBar } from './MailToolBar.svelte';
5
+ export { default as MailingModule } from './MailingModule.svelte';
6
+ export { default as MailingHeader } from './MailingHeader.svelte';
7
+ export { default as MailingMessageViewer } from './MailingMessageViewer.svelte';
@@ -0,0 +1,126 @@
1
+ import type { CrudResult, PaginatedResult, TableFilter } from '../../index.js';
2
+ import type { Snippet } from 'svelte';
3
+ export interface MailPageInfo {
4
+ currentPage: number;
5
+ pageSize: number;
6
+ totalCount: number;
7
+ hasNextPage: boolean;
8
+ hasPreviousPage: boolean;
9
+ }
10
+ export interface MailPaginatorProps extends MailPageInfo {
11
+ onNextClick: () => void;
12
+ onPreviousClick: () => void;
13
+ }
14
+ export type MailFavariteToggleType = 'favorite' | 'unfavorite';
15
+ export type MailMarkReadToggleType = 'read' | 'unread';
16
+ export interface MailToolBarProps {
17
+ onBackClick: () => void;
18
+ onRefreshClick: () => void;
19
+ onComposeClick?: () => void;
20
+ selectedMails?: number[];
21
+ showComposeButton?: boolean;
22
+ showBackButton?: boolean;
23
+ pageInfo?: MailPageInfo;
24
+ showPagination?: boolean;
25
+ showSearch?: boolean;
26
+ customFilterComponent?: Snippet;
27
+ onsearchChange?: (searchTerm: string) => void;
28
+ onNextPageClick?: () => void;
29
+ onPrevPageClick?: () => void;
30
+ showArchiveButton?: boolean;
31
+ onArchiveClick?: () => void;
32
+ showDeleteButton?: boolean;
33
+ onDeleteClick?: () => void;
34
+ showMarkReadButton?: boolean;
35
+ onToggleMarkReadClick?: (val: MailMarkReadToggleType) => void;
36
+ showFavoriteButton?: boolean;
37
+ isReadActive?: boolean;
38
+ onToggleFavoriteClick?: (val: MailFavariteToggleType) => void;
39
+ showMarkAsSpamButton?: boolean;
40
+ onMarkAsSpamClick?: () => void;
41
+ isFavoriteActive?: boolean;
42
+ }
43
+ export interface MailMenu {
44
+ icon: string;
45
+ title: string;
46
+ count: number;
47
+ path: string;
48
+ }
49
+ export interface MailSidebar {
50
+ menus: MailMenu[];
51
+ setActiveMenu?: (val: MailMenu) => boolean;
52
+ onClick?: (val: MailMenu) => void;
53
+ }
54
+ export interface MailingModuleProps {
55
+ showSidePanel?: boolean;
56
+ showPagination?: boolean;
57
+ showComposeButton?: boolean;
58
+ showSearch?: boolean;
59
+ customFilterComponent?: Snippet;
60
+ showArchiveButton?: boolean;
61
+ showDeleteButton?: boolean;
62
+ showMarkReadButton?: boolean;
63
+ showFavoriteButton?: boolean;
64
+ showMarkAsSpamButton?: boolean;
65
+ readInbox: (skip?: number, take?: number, filter?: TableFilter<any>) => Promise<PaginatedResult<MailingMessage>> | PaginatedResult<MailingMessage> | null;
66
+ readOutbox?: (skip?: number, take?: number, filter?: TableFilter<any>) => Promise<PaginatedResult<MailingMessage>> | PaginatedResult<MailingMessage> | null;
67
+ toggleArchieve?: (id: string | number) => Promise<CrudResult<any>> | CrudResult<any> | null;
68
+ toggleSpam?: (id: string | number) => Promise<CrudResult<any>> | CrudResult<any> | null;
69
+ deleteEntry?: (id: string | number) => Promise<CrudResult<any>> | CrudResult<any> | null;
70
+ toggleAsRead?: (id: string | number) => Promise<CrudResult<any>> | CrudResult<any> | null;
71
+ toggleFavourite?: (id: string | number) => Promise<CrudResult<any>> | CrudResult<any> | null;
72
+ toggelImportant?: (id: string | number) => Promise<CrudResult<any>> | CrudResult<any> | null;
73
+ readAMessage: (id: string | number) => Promise<CrudResult<any>> | CrudResult<any> | null;
74
+ }
75
+ export interface MailingMessageCardChecked {
76
+ id: number;
77
+ checked: boolean;
78
+ }
79
+ export interface MailingMessage {
80
+ id: number;
81
+ sender: string;
82
+ subject: string;
83
+ date: Date;
84
+ message: string;
85
+ notes?: string;
86
+ isStared: boolean;
87
+ isImportant: boolean;
88
+ isRead: boolean;
89
+ isChecked?: boolean;
90
+ isSent?: boolean;
91
+ isHtml?: boolean;
92
+ refEntityId?: number;
93
+ receiver: string;
94
+ user?: {
95
+ id: number;
96
+ firstName: string;
97
+ surname: string;
98
+ staffNumber?: string;
99
+ };
100
+ }
101
+ export interface MailingMessageCardProps extends MailingMessage {
102
+ onItemSelected?: (id: number) => void;
103
+ onItemChecked?: (val: MailingMessageCardChecked) => void;
104
+ toggelImportant?: (id: number) => void;
105
+ toggleFavorited?: (id: number) => void;
106
+ }
107
+ export interface MailingMessageViewerProps {
108
+ readMessage: (id: number) => Promise<CrudResult<MailingMessage>> | CrudResult<MailingMessage> | null;
109
+ recordId: number;
110
+ updatePageInfo?: (val: MailPageInfo) => void;
111
+ }
112
+ export interface MailingHeaderData {
113
+ subject: string;
114
+ user: {
115
+ firstName: string;
116
+ surname: string;
117
+ staffNumber: string;
118
+ initials: string;
119
+ };
120
+ to: string;
121
+ }
122
+ export type MailingReplyType = 'reply' | 'reply-all' | 'forward';
123
+ export interface MailingHeaderProps {
124
+ data: MailingHeaderData;
125
+ replyType: MailingReplyType | undefined;
126
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -16,3 +16,4 @@ export { radio, radioButton } from '../forms/radio/index.js';
16
16
  export { checkbox, checkboxButton } from '../forms/checkbox/index.js';
17
17
  export { accordion, accordionItem } from '../ui/accordion/index.js';
18
18
  export { tabs, tabItem } from '../ui/tab/theme.js';
19
+ export { tooltip } from '../ui/tooltip/index.js';
@@ -16,3 +16,4 @@ export { radio, radioButton } from '../forms/radio/index.js';
16
16
  export { checkbox, checkboxButton } from '../forms/checkbox/index.js';
17
17
  export { accordion, accordionItem } from '../ui/accordion/index.js';
18
18
  export { tabs, tabItem } from '../ui/tab/theme.js';
19
+ export { tooltip } from '../ui/tooltip/index.js';
@@ -23,6 +23,7 @@ import type { CheckboxVariants } from '../forms/checkbox/theme.js';
23
23
  import type { AccordionItemVariants, AccordionVariants } from '../ui/accordion/theme.js';
24
24
  import type { TabsVaraints } from '../ui/tab/theme.js';
25
25
  import type { ACTION_BUTTON_KINDS } from '../ui/buttons/ActionButton.svelte';
26
+ import type { TooltipVariants } from '../ui/tooltip/theme.js';
26
27
  export interface TFSidebarProps {
27
28
  homeUrl: string;
28
29
  logoUrl: string;
@@ -616,6 +617,7 @@ export interface PaginateProps {
616
617
  hiddenColumns?: string[];
617
618
  tableColumns?: any[];
618
619
  recordCount?: number;
620
+ pageSize?: number;
619
621
  }
620
622
  export interface PageInfo {
621
623
  hasNextPage: boolean;
@@ -877,3 +879,5 @@ export interface FormFileUploadProps {
877
879
  contextKey?: any;
878
880
  onChange?: (val: any) => void;
879
881
  }
882
+ export interface TooltipProps extends TooltipVariants, PopperProps {
883
+ }
@@ -1,10 +1,14 @@
1
1
  <script lang="ts">
2
2
  import type { PageLoaderProps } from '../../index.js';
3
+ import IconifyIcon from '../icons/IconifyIcon.svelte';
3
4
 
4
5
  let { size = 70, iconColor = 'text-blue-400' }: PageLoaderProps = $props();
5
6
  </script>
6
7
 
7
8
  <div class="grid h-full w-full items-center justify-center">
8
- <iconify-icon class={iconColor} icon="svg-spinners:blocks-shuffle-3" style="font-size: {size}px;"
9
- ></iconify-icon>
9
+ <IconifyIcon
10
+ class={iconColor}
11
+ icon="svg-spinners:blocks-shuffle-3"
12
+ style="font-size: {size}px;"
13
+ />
10
14
  </div>
@@ -18,7 +18,7 @@
18
18
  iconColor?: string;
19
19
  style?: any;
20
20
  action?: {
21
- label: string;
21
+ label: string | boolean;
22
22
  onClick: () => void;
23
23
  buttonStyle?: string;
24
24
  };
@@ -10,7 +10,7 @@ export interface CustomToastOptions extends ToastOptions {
10
10
  iconColor?: string;
11
11
  style?: any;
12
12
  action?: {
13
- label: string;
13
+ label: string | boolean;
14
14
  onClick: () => void;
15
15
  buttonStyle?: string;
16
16
  };
@@ -0,0 +1,51 @@
1
+ <script lang="ts">
2
+ import { Popper, type TooltipProps, type TriggeredToggleEvent } from '../../index.js';
3
+ import clsx from 'clsx';
4
+ import { tooltip } from './theme.js';
5
+
6
+ let {
7
+ type = 'dark',
8
+ color = undefined,
9
+ trigger = 'hover',
10
+ arrow = true,
11
+ children,
12
+ placement = 'top',
13
+ onbeforetoggle: _onbeforetoggle,
14
+ class: className,
15
+ isOpen = $bindable(false),
16
+ ...restProps
17
+ }: TooltipProps = $props();
18
+
19
+ const base = $derived(tooltip({ color, type, class: clsx(className) }));
20
+ function onbeforetoggle(ev: TriggeredToggleEvent) {
21
+ // block all focusable elements inside the tooltip
22
+ if (ev.target instanceof HTMLElement) {
23
+ ev.target
24
+ .querySelectorAll(
25
+ 'a, button, input, textarea, select, details, [tabindex], [contenteditable="true"]'
26
+ )
27
+ .forEach((element) => element.setAttribute('tabindex', '-1'));
28
+ }
29
+ // bubble event to parent
30
+ _onbeforetoggle?.(ev);
31
+ }
32
+ </script>
33
+
34
+ <Popper {...restProps} bind:isOpen {placement} {trigger} {arrow} class={base} {onbeforetoggle}>
35
+ <div class="pointer-events-none">{@render children()}</div>
36
+ </Popper>
37
+
38
+ <!--
39
+ @component
40
+ ## Props
41
+ @prop type = "dark"
42
+ @prop color = undefined
43
+ @prop trigger = "hover"
44
+ @prop arrow = true
45
+ @prop children
46
+ @prop placement = "top"
47
+ @prop onbeforetoggle: _onbeforetoggle
48
+ @prop class: className
49
+ @prop isOpen = $bindable(false)
50
+ @prop ...restProps
51
+ -->