@caratlogic/design-system 0.1.10 → 0.1.12
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/dist/components/layouts/AppShell/AppShell.types.d.ts +14 -1
- package/dist/components/layouts/AppShell/AppShell.types.d.ts.map +1 -1
- package/dist/components/layouts/AppShell/DashboardShell.d.ts.map +1 -1
- package/dist/components/molecules/InAppNotificationCard/InAppNotificationCard.accessibility.d.ts +4 -0
- package/dist/components/molecules/InAppNotificationCard/InAppNotificationCard.accessibility.d.ts.map +1 -0
- package/dist/components/molecules/InAppNotificationCard/InAppNotificationCard.d.ts +8 -0
- package/dist/components/molecules/InAppNotificationCard/InAppNotificationCard.d.ts.map +1 -0
- package/dist/components/molecules/InAppNotificationCard/InAppNotificationCard.types.d.ts +22 -0
- package/dist/components/molecules/InAppNotificationCard/InAppNotificationCard.types.d.ts.map +1 -0
- package/dist/components/molecules/InAppNotificationCard/InAppNotificationCard.utils.d.ts +4 -0
- package/dist/components/molecules/InAppNotificationCard/InAppNotificationCard.utils.d.ts.map +1 -0
- package/dist/components/molecules/InAppNotificationCard/index.d.ts +4 -0
- package/dist/components/molecules/InAppNotificationCard/index.d.ts.map +1 -0
- package/dist/components/organisms/InAppNotificationsPanel/InAppNotificationsPanel.accessibility.d.ts +9 -0
- package/dist/components/organisms/InAppNotificationsPanel/InAppNotificationsPanel.accessibility.d.ts.map +1 -0
- package/dist/components/organisms/InAppNotificationsPanel/InAppNotificationsPanel.d.ts +9 -0
- package/dist/components/organisms/InAppNotificationsPanel/InAppNotificationsPanel.d.ts.map +1 -0
- package/dist/components/organisms/InAppNotificationsPanel/InAppNotificationsPanel.hooks.d.ts +12 -0
- package/dist/components/organisms/InAppNotificationsPanel/InAppNotificationsPanel.hooks.d.ts.map +1 -0
- package/dist/components/organisms/InAppNotificationsPanel/InAppNotificationsPanel.types.d.ts +41 -0
- package/dist/components/organisms/InAppNotificationsPanel/InAppNotificationsPanel.types.d.ts.map +1 -0
- package/dist/components/organisms/InAppNotificationsPanel/InAppNotificationsPanel.utils.d.ts +4 -0
- package/dist/components/organisms/InAppNotificationsPanel/InAppNotificationsPanel.utils.d.ts.map +1 -0
- package/dist/components/organisms/InAppNotificationsPanel/index.d.ts +5 -0
- package/dist/components/organisms/InAppNotificationsPanel/index.d.ts.map +1 -0
- package/dist/components/organisms/MediaGallery/MediaGallery.d.ts +1 -1
- package/dist/components/organisms/MediaGallery/MediaGallery.d.ts.map +1 -1
- package/dist/components/organisms/MediaGallery/MediaGallery.utils.d.ts +6 -0
- package/dist/components/organisms/MediaGallery/MediaGallery.utils.d.ts.map +1 -1
- package/dist/components/organisms/Navbar/Navbar.d.ts +1 -1
- package/dist/components/organisms/Navbar/Navbar.d.ts.map +1 -1
- package/dist/constants/filePatterns.d.ts +3 -0
- package/dist/constants/filePatterns.d.ts.map +1 -1
- package/dist/index.cjs.js +184 -19
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +180 -20
- package/dist/index.esm.js.map +1 -1
- package/dist/utils/relativeTime.d.ts +6 -0
- package/dist/utils/relativeTime.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -43,6 +43,7 @@ export * from './components/molecules/DropdownMenu';
|
|
|
43
43
|
export * from './components/molecules/EntityHeader';
|
|
44
44
|
export * from './components/molecules/Field';
|
|
45
45
|
export * from './components/molecules/FilterSelect';
|
|
46
|
+
export * from './components/molecules/InAppNotificationCard';
|
|
46
47
|
export * from './components/molecules/FormSectionCard';
|
|
47
48
|
export * from './components/molecules/InfoBanner';
|
|
48
49
|
export * from './components/molecules/InventoryComboBox';
|
|
@@ -82,6 +83,7 @@ export * from './components/organisms/AdvancedSearchDrawer';
|
|
|
82
83
|
export * from './components/organisms/AuditHistoryPanel';
|
|
83
84
|
export * from './components/organisms/CustomizeColumnsDrawer';
|
|
84
85
|
export * from './components/organisms/FileUploader';
|
|
86
|
+
export * from './components/organisms/InAppNotificationsPanel';
|
|
85
87
|
export * from './components/organisms/InventoryItemCard';
|
|
86
88
|
export * from './components/organisms/MediaGallery';
|
|
87
89
|
export * from './components/organisms/Navbar';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.esm.js
CHANGED
|
@@ -2668,12 +2668,12 @@ const createLucideIcon = (iconName, iconNode) => {
|
|
|
2668
2668
|
*/
|
|
2669
2669
|
|
|
2670
2670
|
|
|
2671
|
-
const __iconNode$
|
|
2671
|
+
const __iconNode$18 = [
|
|
2672
2672
|
["rect", { width: "20", height: "5", x: "2", y: "3", rx: "1", key: "1wp1u1" }],
|
|
2673
2673
|
["path", { d: "M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8", key: "1s80jp" }],
|
|
2674
2674
|
["path", { d: "M10 12h4", key: "a56b0p" }]
|
|
2675
2675
|
];
|
|
2676
|
-
const Archive = createLucideIcon("archive", __iconNode$
|
|
2676
|
+
const Archive = createLucideIcon("archive", __iconNode$18);
|
|
2677
2677
|
|
|
2678
2678
|
/**
|
|
2679
2679
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2683,11 +2683,11 @@ const Archive = createLucideIcon("archive", __iconNode$17);
|
|
|
2683
2683
|
*/
|
|
2684
2684
|
|
|
2685
2685
|
|
|
2686
|
-
const __iconNode$
|
|
2686
|
+
const __iconNode$17 = [
|
|
2687
2687
|
["path", { d: "m12 19-7-7 7-7", key: "1l729n" }],
|
|
2688
2688
|
["path", { d: "M19 12H5", key: "x3x0zl" }]
|
|
2689
2689
|
];
|
|
2690
|
-
const ArrowLeft = createLucideIcon("arrow-left", __iconNode$
|
|
2690
|
+
const ArrowLeft = createLucideIcon("arrow-left", __iconNode$17);
|
|
2691
2691
|
|
|
2692
2692
|
/**
|
|
2693
2693
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2697,11 +2697,11 @@ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$16);
|
|
|
2697
2697
|
*/
|
|
2698
2698
|
|
|
2699
2699
|
|
|
2700
|
-
const __iconNode$
|
|
2700
|
+
const __iconNode$16 = [
|
|
2701
2701
|
["path", { d: "M5 12h14", key: "1ays0h" }],
|
|
2702
2702
|
["path", { d: "m12 5 7 7-7 7", key: "xquz4c" }]
|
|
2703
2703
|
];
|
|
2704
|
-
const ArrowRight = createLucideIcon("arrow-right", __iconNode$
|
|
2704
|
+
const ArrowRight = createLucideIcon("arrow-right", __iconNode$16);
|
|
2705
2705
|
|
|
2706
2706
|
/**
|
|
2707
2707
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -2711,11 +2711,32 @@ const ArrowRight = createLucideIcon("arrow-right", __iconNode$15);
|
|
|
2711
2711
|
*/
|
|
2712
2712
|
|
|
2713
2713
|
|
|
2714
|
-
const __iconNode$
|
|
2714
|
+
const __iconNode$15 = [
|
|
2715
2715
|
["path", { d: "M4.929 4.929 19.07 19.071", key: "196cmz" }],
|
|
2716
2716
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]
|
|
2717
2717
|
];
|
|
2718
|
-
const Ban = createLucideIcon("ban", __iconNode$
|
|
2718
|
+
const Ban = createLucideIcon("ban", __iconNode$15);
|
|
2719
|
+
|
|
2720
|
+
/**
|
|
2721
|
+
* @license lucide-react v0.539.0 - ISC
|
|
2722
|
+
*
|
|
2723
|
+
* This source code is licensed under the ISC license.
|
|
2724
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
2725
|
+
*/
|
|
2726
|
+
|
|
2727
|
+
|
|
2728
|
+
const __iconNode$14 = [
|
|
2729
|
+
["path", { d: "M10.268 21a2 2 0 0 0 3.464 0", key: "vwvbt9" }],
|
|
2730
|
+
[
|
|
2731
|
+
"path",
|
|
2732
|
+
{
|
|
2733
|
+
d: "M13.916 2.314A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.74 7.327A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673 9 9 0 0 1-.585-.665",
|
|
2734
|
+
key: "1tip0g"
|
|
2735
|
+
}
|
|
2736
|
+
],
|
|
2737
|
+
["circle", { cx: "18", cy: "8", r: "3", key: "1g0gzu" }]
|
|
2738
|
+
];
|
|
2739
|
+
const BellDot = createLucideIcon("bell-dot", __iconNode$14);
|
|
2719
2740
|
|
|
2720
2741
|
/**
|
|
2721
2742
|
* @license lucide-react v0.539.0 - ISC
|
|
@@ -28227,6 +28248,53 @@ const FilterSelect = ({ label, value, onValueChange, options, resetValue = 'all'
|
|
|
28227
28248
|
return (jsxs(Select, { value: value, onValueChange: onValueChange, keepOpenOnSelect: true, children: [jsxs(SelectTrigger, { className: cn(TRIGGER_BASE, active && TRIGGER_ACTIVE, triggerClassName), children: [jsx(Funnel, { className: cn('h-4 w-4 shrink-0', active ? 'text-primary' : 'text-muted-foreground'), "aria-hidden": "true" }), jsxs("span", { className: "flex items-center gap-1", children: [jsx(SelectValue, { placeholder: label }), active && (jsx("span", { className: "ml-1 inline-flex h-4 min-w-4 items-center justify-center rounded bg-primary/10 px-1 text-[10px] font-semibold leading-none text-primary", children: activeCount }))] })] }), jsxs(SelectContent, { className: cn(CONTENT_BASE, contentClassName), searchable: searchable, children: [jsx(SelectItem, { value: resetValue, withCheckbox: true, children: label }), options.map((opt) => (jsx(SelectItem, { value: opt.value, searchValue: opt.searchValue, withCheckbox: true, children: opt.label }, opt.value)))] })] }));
|
|
28228
28249
|
};
|
|
28229
28250
|
|
|
28251
|
+
/**
|
|
28252
|
+
* Compact "time ago" label, e.g. "5m ago". Falls back to a locale date past a
|
|
28253
|
+
* week so older entries stay scannable.
|
|
28254
|
+
*/
|
|
28255
|
+
function formatRelativeTime(value) {
|
|
28256
|
+
if (!value)
|
|
28257
|
+
return '';
|
|
28258
|
+
const then = value instanceof Date ? value.getTime() : new Date(value).getTime();
|
|
28259
|
+
if (Number.isNaN(then))
|
|
28260
|
+
return '';
|
|
28261
|
+
const minutes = Math.floor((Date.now() - then) / 60000);
|
|
28262
|
+
if (minutes < 1)
|
|
28263
|
+
return 'Just now';
|
|
28264
|
+
if (minutes < 60)
|
|
28265
|
+
return `${minutes}m ago`;
|
|
28266
|
+
const hours = Math.floor(minutes / 60);
|
|
28267
|
+
if (hours < 24)
|
|
28268
|
+
return `${hours}h ago`;
|
|
28269
|
+
const days = Math.floor(hours / 24);
|
|
28270
|
+
if (days < 7)
|
|
28271
|
+
return `${days}d ago`;
|
|
28272
|
+
return new Date(then).toLocaleDateString();
|
|
28273
|
+
}
|
|
28274
|
+
|
|
28275
|
+
/** Read entries sit flat on the surface; unread ones get a primary wash. */
|
|
28276
|
+
function getInAppNotificationCardClasses(isRead, className) {
|
|
28277
|
+
return cn('flex h-[5.125rem] w-full cursor-pointer gap-2.5 rounded-lg border px-3 py-3 text-left transition-colors', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50', isRead
|
|
28278
|
+
? 'border-border bg-card hover:bg-muted/40'
|
|
28279
|
+
: 'border-primary/20 bg-primary/5 hover:bg-primary/10', className);
|
|
28280
|
+
}
|
|
28281
|
+
function getInAppNotificationIconClasses(isRead) {
|
|
28282
|
+
return cn('mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-full', isRead ? 'bg-muted text-muted-foreground' : 'bg-primary/10 text-primary');
|
|
28283
|
+
}
|
|
28284
|
+
|
|
28285
|
+
const inAppNotificationCardA11y = {
|
|
28286
|
+
unreadLabel: 'Unread',
|
|
28287
|
+
};
|
|
28288
|
+
|
|
28289
|
+
/**
|
|
28290
|
+
* One row in a notification list. Unread state is signalled by a dot, a tinted
|
|
28291
|
+
* surface and a heavier title, so it never relies on colour alone.
|
|
28292
|
+
*/
|
|
28293
|
+
const InAppNotificationCard = ({ notification, onSelect, defaultIcon, className, }) => {
|
|
28294
|
+
const { title, message, createdAt, isRead, subject, icon } = notification;
|
|
28295
|
+
return (jsxs("button", { type: "button", onClick: () => onSelect(notification), className: getInAppNotificationCardClasses(isRead, className), children: [jsx("span", { className: getInAppNotificationIconClasses(isRead), children: icon ?? defaultIcon ?? (jsx(BellDot, { className: "size-4", "aria-hidden": "true" })) }), jsxs("span", { className: "min-w-0 flex-1", children: [jsxs("span", { className: "flex items-baseline gap-2", children: [!isRead && (jsx("span", { role: "img", "aria-label": inAppNotificationCardA11y.unreadLabel, className: "size-1.5 shrink-0 rounded-full bg-primary" })), jsx("span", { className: cn('min-w-0 flex-1 truncate text-sm text-foreground', isRead ? 'font-medium' : 'font-semibold'), children: title }), jsx("time", { className: "shrink-0 text-[0.6875rem] text-muted-foreground tabular-nums", children: formatRelativeTime(createdAt) })] }), jsx("span", { className: "mt-1 line-clamp-1 text-xs text-secondary-foreground", children: message }), subject && (jsx("span", { className: "mt-0.5 block truncate text-[0.6875rem] font-medium text-muted-foreground", children: subject }))] })] }));
|
|
28296
|
+
};
|
|
28297
|
+
|
|
28230
28298
|
const HEADER_TONE_CLASSES = {
|
|
28231
28299
|
neutral: 'bg-[var(--section-header)]',
|
|
28232
28300
|
gem: 'bg-primary/5 dark:bg-[#173626]',
|
|
@@ -64641,6 +64709,8 @@ const FILE_TYPE_PATTERNS = {
|
|
|
64641
64709
|
DOCUMENT: /\.(doc|docx|xls|xlsx|ppt|pptx)($|\?)/i,
|
|
64642
64710
|
VIDEO: /\.(mp4|m4v|avi|mov|wmv|flv|webm|mkv|ogv|mpe?g|3gp)($|\?)/i,
|
|
64643
64711
|
AUDIO: /\.(mp3|wav|flac|aac|ogg)($|\?)/i,
|
|
64712
|
+
/** Interactive viewer pages (supplier 360° spinners), not media files. */
|
|
64713
|
+
EMBED: /\.html?($|\?|#)/i,
|
|
64644
64714
|
};
|
|
64645
64715
|
const isFileType = {
|
|
64646
64716
|
pdf: (url) => FILE_TYPE_PATTERNS.PDF.test(url),
|
|
@@ -64648,6 +64718,7 @@ const isFileType = {
|
|
|
64648
64718
|
document: (url) => FILE_TYPE_PATTERNS.DOCUMENT.test(url),
|
|
64649
64719
|
video: (url) => FILE_TYPE_PATTERNS.VIDEO.test(url),
|
|
64650
64720
|
audio: (url) => FILE_TYPE_PATTERNS.AUDIO.test(url),
|
|
64721
|
+
embed: (url) => FILE_TYPE_PATTERNS.EMBED.test(url),
|
|
64651
64722
|
};
|
|
64652
64723
|
|
|
64653
64724
|
/** Seek to ~1st frame for static video thumbnails (HTML5 media fragment). */
|
|
@@ -64663,6 +64734,12 @@ const createVideoMediaItem = (src, index, idPrefix = 'vid') => ({
|
|
|
64663
64734
|
src,
|
|
64664
64735
|
thumbSrc: videoThumbnailSrc(src),
|
|
64665
64736
|
});
|
|
64737
|
+
/**
|
|
64738
|
+
* True when a "video" is really an interactive viewer page. Supplier 360°
|
|
64739
|
+
* spinners (Vision360, Varni) serve `text/html`, so `<video>` renders nothing
|
|
64740
|
+
* and there is no frame to seek for a thumbnail — they need an iframe.
|
|
64741
|
+
*/
|
|
64742
|
+
const isEmbedMediaItem = (item) => item.kind === 'video' && isFileType.embed(item.src);
|
|
64666
64743
|
const isPdfMediaItem = (item) => item.isPdf === true ||
|
|
64667
64744
|
isFileType.pdf(item.src) ||
|
|
64668
64745
|
(item.kind === 'certificate' && !isFileType.image(item.src));
|
|
@@ -65616,6 +65693,71 @@ const FileUploader = ({ accept, multiple = true, maxSize = 50, maxFiles = 5, lab
|
|
|
65616
65693
|
return (jsxs("div", { className: cn('flex flex-col gap-4', className), children: [label && (jsx("label", { className: "text-sm font-medium text-foreground", children: label })), jsx(DropZone, { uploadSubject: uploadSubject, supportedFormats: supportedFormats, maxSize: maxSize, maxFiles: maxFiles, accept: accept, multiple: multiple, disabled: disabled, onFiles: handlePickerFiles }), files.length > 0 && (jsxs("div", { className: "space-y-2", children: [jsx("p", { className: "text-[13px] text-label", children: "Uploaded File" }), jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: onDragEnd, children: jsx(SortableContext, { items: files.map((f) => f.id), strategy: rectSortingStrategy, children: jsx("div", { className: "flex flex-wrap gap-3", children: files.map((file) => (jsx(FileCard, { file: file, sortable: sortable, disabled: disabled, onRemove: handleRemove, onPreview: previewFile }, file.id))) }) }) })] })), enableUrlInput && (jsxs(Fragment$2, { children: [jsxs("div", { className: "flex items-center gap-3 text-sm font-normal text-label", children: [jsx("span", { className: "h-px flex-1 bg-border" }), jsx("span", { children: "or" }), jsx("span", { className: "h-px flex-1 bg-border" })] }), jsx(UrlImportRow, { disabled: disabled, onAdd: handleAddUrl })] })), cropImages && currentCropFile && cropPreviewUrl && (jsx(ImageCropModal, { open: true, imageUrl: cropPreviewUrl, fileName: currentCropFile.name, fileType: currentCropFile.type, onCancel: handleCropCancel, onConfirm: handleCropConfirm }))] }));
|
|
65617
65694
|
};
|
|
65618
65695
|
|
|
65696
|
+
/** Falls back to counting the current page when the caller has no total. */
|
|
65697
|
+
function resolveUnreadCount(notifications, unreadCount) {
|
|
65698
|
+
if (typeof unreadCount === 'number')
|
|
65699
|
+
return Math.max(0, unreadCount);
|
|
65700
|
+
return notifications.filter((notification) => !notification.isRead).length;
|
|
65701
|
+
}
|
|
65702
|
+
|
|
65703
|
+
// 1. React
|
|
65704
|
+
/** Derived display state for the panel header and body. */
|
|
65705
|
+
function useInAppNotificationsPanel(notifications, unreadCount) {
|
|
65706
|
+
return useMemo(() => {
|
|
65707
|
+
const resolved = resolveUnreadCount(notifications, unreadCount);
|
|
65708
|
+
return {
|
|
65709
|
+
unreadCount: resolved,
|
|
65710
|
+
hasUnread: resolved > 0,
|
|
65711
|
+
isEmpty: notifications.length === 0,
|
|
65712
|
+
};
|
|
65713
|
+
}, [notifications, unreadCount]);
|
|
65714
|
+
}
|
|
65715
|
+
/**
|
|
65716
|
+
* Fires `onLoadMore` when the sentinel scrolls into view inside `rootRef`.
|
|
65717
|
+
* No-ops where IntersectionObserver is unavailable (jsdom, older browsers), so
|
|
65718
|
+
* the list simply stops auto-loading rather than breaking.
|
|
65719
|
+
*/
|
|
65720
|
+
function useInfiniteScrollSentinel(rootRef, onLoadMore, enabled) {
|
|
65721
|
+
const sentinelRef = useRef(null);
|
|
65722
|
+
useEffect(() => {
|
|
65723
|
+
const sentinel = sentinelRef.current;
|
|
65724
|
+
if (!sentinel || !enabled || !onLoadMore)
|
|
65725
|
+
return;
|
|
65726
|
+
if (typeof IntersectionObserver === 'undefined')
|
|
65727
|
+
return;
|
|
65728
|
+
const observer = new IntersectionObserver((entries) => {
|
|
65729
|
+
if (entries.some((entry) => entry.isIntersecting))
|
|
65730
|
+
onLoadMore();
|
|
65731
|
+
},
|
|
65732
|
+
// Start fetching slightly before the sentinel is actually visible.
|
|
65733
|
+
{ root: rootRef.current, rootMargin: '80px' });
|
|
65734
|
+
observer.observe(sentinel);
|
|
65735
|
+
return () => observer.disconnect();
|
|
65736
|
+
}, [rootRef, onLoadMore, enabled]);
|
|
65737
|
+
return sentinelRef;
|
|
65738
|
+
}
|
|
65739
|
+
|
|
65740
|
+
const inAppNotificationsPanelA11y = {
|
|
65741
|
+
panelLabel: 'Notifications',
|
|
65742
|
+
listLabel: 'Notification list',
|
|
65743
|
+
markAllReadLabel: 'Mark all notifications as read',
|
|
65744
|
+
retryLabel: 'Retry loading notifications',
|
|
65745
|
+
};
|
|
65746
|
+
/** Non-modal dropdown, so `dialog` rather than `alertdialog`. */
|
|
65747
|
+
const IN_APP_NOTIFICATIONS_PANEL_ROLE = 'dialog';
|
|
65748
|
+
|
|
65749
|
+
/**
|
|
65750
|
+
* Notification list with header actions and loading / error / empty states.
|
|
65751
|
+
* Positioning is the caller's concern — render it inside a popover anchored to
|
|
65752
|
+
* whatever opens it (see `DashboardShell`'s `notificationsPanel` slot).
|
|
65753
|
+
*/
|
|
65754
|
+
const InAppNotificationsPanel = ({ notifications, onSelect, unreadCount, totalCount, isLoading = false, hasNextPage = false, isFetchingNextPage = false, onLoadMore, isError = false, onRetry, onMarkAllRead, isMarkingAllRead = false, title = inAppNotificationsPanelA11y.panelLabel, emptyTitle = 'No notifications yet', emptyDescription, emptyIcon, emptyState, errorMessage = "Couldn't load notifications.", defaultIcon, className, }) => {
|
|
65755
|
+
const { unreadCount: resolvedUnread, hasUnread, isEmpty, } = useInAppNotificationsPanel(notifications, unreadCount);
|
|
65756
|
+
const listRef = useRef(null);
|
|
65757
|
+
const sentinelRef = useInfiniteScrollSentinel(listRef, onLoadMore, hasNextPage && !isLoading);
|
|
65758
|
+
return (jsxs("div", { role: IN_APP_NOTIFICATIONS_PANEL_ROLE, "aria-label": inAppNotificationsPanelA11y.panelLabel, className: cn('flex w-full flex-col overflow-hidden', className), children: [jsxs("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-border px-2 py-3", children: [jsx("div", { className: "min-w-0", children: jsxs("h2", { className: "flex min-w-0 items-center gap-2 text-sm font-semibold text-foreground", children: [jsx("span", { className: "truncate", children: title }), typeof totalCount === 'number' && (jsx("span", { className: "shrink-0 rounded-full bg-muted px-2 py-0.5 text-[0.6875rem] font-semibold text-muted-foreground tabular-nums", children: totalCount }))] }) }), jsx("span", { className: "flex shrink-0 items-center gap-2", children: hasUnread && onMarkAllRead && (jsx(Button$1, { variant: "ghost", size: "sm", onClick: onMarkAllRead, disabled: isMarkingAllRead, "aria-label": inAppNotificationsPanelA11y.markAllReadLabel, className: "h-7 px-2 text-xs font-medium text-primary hover:text-primary", children: "Mark all as read" })) })] }), jsx("div", { ref: listRef, className: "min-h-0 max-h-[16.75rem] flex-1 overflow-y-auto p-2", children: isLoading ? (jsxs("div", { className: "flex items-center justify-center gap-2 py-10 text-sm text-muted-foreground", children: [jsx(LoaderCircle, { className: "size-4 animate-spin", "aria-hidden": "true" }), "Loading notifications..."] })) : isError ? (jsxs("div", { className: "flex flex-col items-center gap-2 py-10 text-center", children: [jsx("p", { className: "text-sm text-muted-foreground", children: errorMessage }), onRetry && (jsx(Button$1, { variant: "outline", size: "sm", onClick: onRetry, "aria-label": inAppNotificationsPanelA11y.retryLabel, className: "h-7 px-3 text-xs", children: "Try again" }))] })) : isEmpty ? ((emptyState ?? (jsxs("div", { className: "flex flex-col items-center gap-2 px-6 py-10 text-center", children: [jsx("span", { className: "flex size-10 items-center justify-center rounded-full bg-muted", children: emptyIcon ?? (jsx(Bell, { className: "size-5 text-muted-foreground", "aria-hidden": "true" })) }), jsx("p", { className: "text-sm font-medium text-foreground", children: emptyTitle }), emptyDescription && (jsx("p", { className: "max-w-[16rem] text-xs text-muted-foreground", children: emptyDescription }))] })))) : (jsxs("div", { role: "list", "aria-label": inAppNotificationsPanelA11y.listLabel, className: "flex flex-col gap-1.5", children: [notifications.map((notification) => (jsx(InAppNotificationCard, { notification: notification, onSelect: onSelect, defaultIcon: defaultIcon }, notification.id))), hasNextPage && (jsx("div", { ref: sentinelRef, "aria-hidden": "true", className: "h-px" })), isFetchingNextPage && (jsxs("div", { className: "flex items-center justify-center gap-2 py-3 text-xs text-muted-foreground", children: [jsx(LoaderCircle, { className: "size-3.5 animate-spin", "aria-hidden": "true" }), "Loading more..."] }))] })) })] }));
|
|
65759
|
+
};
|
|
65760
|
+
|
|
65619
65761
|
const stop = (fn) => (e) => {
|
|
65620
65762
|
e.stopPropagation();
|
|
65621
65763
|
fn?.();
|
|
@@ -65770,9 +65912,22 @@ const PdfPreview = ({ item }) => {
|
|
|
65770
65912
|
const docsViewer = `https://docs.google.com/gview?embedded=1&url=${encodeURIComponent(item.src)}`;
|
|
65771
65913
|
return (jsx("object", { data: item.src, type: "application/pdf", className: "h-full w-full bg-card", "aria-label": item.name ?? 'Certificate PDF', children: jsx("iframe", { title: item.name ?? 'Certificate PDF', className: "h-full w-full border-0 bg-card", src: docsViewer }) }));
|
|
65772
65914
|
};
|
|
65915
|
+
/**
|
|
65916
|
+
* Videos arrive as either a real file or a supplier's 360° viewer page. The URL
|
|
65917
|
+
* settles most cases, but not every viewer ends in `.html` (v360, loupe360),
|
|
65918
|
+
* so a `<video>` that fails to load falls back to the iframe as well. Remounted
|
|
65919
|
+
* per selection via `key`, which resets that fallback.
|
|
65920
|
+
*/
|
|
65921
|
+
const VideoOrEmbed = ({ item }) => {
|
|
65922
|
+
const [useEmbed, setUseEmbed] = useState(() => isEmbedMediaItem(item));
|
|
65923
|
+
if (useEmbed) {
|
|
65924
|
+
return (jsx("iframe", { src: item.src, title: item.name ?? '360\u00B0 viewer', className: "h-full w-full border-0 bg-card", allowFullScreen: true }));
|
|
65925
|
+
}
|
|
65926
|
+
return (jsx("video", { src: item.src, controls: true, onError: () => setUseEmbed(true), className: "h-full w-full object-cover", "aria-label": item.name ?? 'Video' }));
|
|
65927
|
+
};
|
|
65773
65928
|
const MainMedia = ({ item }) => {
|
|
65774
65929
|
if (item.kind === 'video') {
|
|
65775
|
-
return
|
|
65930
|
+
return jsx(VideoOrEmbed, { item: item });
|
|
65776
65931
|
}
|
|
65777
65932
|
if (isPdfMediaItem(item)) {
|
|
65778
65933
|
return jsx(PdfPreview, { item: item });
|
|
@@ -65782,7 +65937,7 @@ const MainMedia = ({ item }) => {
|
|
|
65782
65937
|
const Thumbnail = ({ item, isActive, onSelect }) => {
|
|
65783
65938
|
const Icon = KIND_ICON[item.kind];
|
|
65784
65939
|
const isPdf = isPdfMediaItem(item);
|
|
65785
|
-
const isVideoWithoutThumb = item.kind === 'video' && !item.thumbSrc;
|
|
65940
|
+
const isVideoWithoutThumb = item.kind === 'video' && (!item.thumbSrc || isEmbedMediaItem(item));
|
|
65786
65941
|
return (jsxs("button", { type: "button", onClick: onSelect, "aria-label": `Select ${item.name ?? item.kind}`, "aria-pressed": isActive, className: cn('group relative flex aspect-square w-full cursor-pointer overflow-hidden rounded-lg border transition-colors', isActive
|
|
65787
65942
|
? 'border-primary ring-2 ring-primary/30'
|
|
65788
65943
|
: 'border-border hover:border-primary/40'), children: [isPdf ? (jsxs("span", { className: "flex h-full w-full flex-col items-center justify-center gap-1 bg-muted p-2 text-muted-foreground", children: [jsx(Icon, { size: 20 }), jsx("span", { className: "text-[10px] font-medium uppercase", children: "PDF" })] })) : isVideoWithoutThumb ? (jsx("div", { className: "h-full w-full flex items-center justify-center bg-muted", children: jsx(Icon, { size: 24, className: "text-muted-foreground" }) })) : item.kind === 'video' ? (jsx("video", { src: item.thumbSrc ?? item.src, muted: true, playsInline: true, preload: "metadata", className: "h-full w-full object-cover", "aria-hidden": "true" })) : (jsx("img", { src: item.thumbSrc ?? item.src, alt: "", className: "h-full w-full object-cover" })), !isPdf && item.kind !== 'image' && !isVideoWithoutThumb && (jsx("span", { className: "pointer-events-none absolute inset-0 flex items-center justify-center bg-black/30 text-white", children: jsx(Icon, { size: 20 }) })), isVideoWithoutThumb && (jsx("span", { className: "pointer-events-none absolute inset-0 flex items-center justify-center bg-black/30" }))] }));
|
|
@@ -65803,7 +65958,7 @@ const MediaGallery = ({ items, thumbsVisible = 4, hideTabs = false, mainAspectCl
|
|
|
65803
65958
|
(kinds.length > 0 ? (jsx(Tabs, { value: activeKind ?? undefined, onValueChange: (v) => setActiveKind(v), tabStyle: "boxed", size: "sm", children: jsx(TabsList, { children: kinds.map((kind) => {
|
|
65804
65959
|
const Icon = KIND_ICON[kind];
|
|
65805
65960
|
return (jsx(TabsTrigger, { value: kind, icon: jsx(Icon, { size: 14 }), children: MEDIA_KIND_LABEL[kind] }, kind));
|
|
65806
|
-
}) }) })) : (jsx("div", { className: "h-9", "aria-hidden": "true" }))), selected && isZoomableImage ? (jsxs("div", { className: "relative", children: [jsx(ZoomSplitViewer, { src: selected.src, alt: selected.name ?? 'Media' }), !hideDownload && (jsx("div", { className: "absolute right-3 top-3 z-20", children: jsx("button", { type: "button", onClick: handleDownload, "aria-label": "Download media", className: "inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-md border border-border bg-card text-foreground transition-all hover:border-primary hover:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:border-primary focus-visible:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:outline-none", children: jsx(Download, { className: "h-4 w-4" }) }) }))] })) : selected ? (jsxs("div", { className: cn('relative overflow-hidden rounded-xl border border-border bg-muted', mainAspectClassName), children: [jsx(MainMedia, { item: selected }), !hideDownload && (jsx("div", { className: "absolute right-3 top-3", children: jsx("button", { type: "button", onClick: handleDownload, "aria-label": "Download media", className: "inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-md border border-border bg-card text-foreground transition-all hover:border-primary hover:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:border-primary focus-visible:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:outline-none", children: jsx(Download, { className: "h-4 w-4" }) }) }))] })) : (jsx("div", { className: cn('flex items-center justify-center rounded-xl border border-dashed border-border bg-muted/40 text-sm text-muted-foreground', mainAspectClassName), children: emptyText })), visibleItems.length > 1 && (jsx("div", { className: "grid gap-3", style: {
|
|
65961
|
+
}) }) })) : (jsx("div", { className: "h-9", "aria-hidden": "true" }))), selected && isZoomableImage ? (jsxs("div", { className: "relative", children: [jsx(ZoomSplitViewer, { src: selected.src, alt: selected.name ?? 'Media' }), !hideDownload && (jsx("div", { className: "absolute right-3 top-3 z-20", children: jsx("button", { type: "button", onClick: handleDownload, "aria-label": "Download media", className: "inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-md border border-border bg-card text-foreground transition-all hover:border-primary hover:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:border-primary focus-visible:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:outline-none", children: jsx(Download, { className: "h-4 w-4" }) }) }))] })) : selected ? (jsxs("div", { className: cn('relative overflow-hidden rounded-xl border border-border bg-muted', mainAspectClassName), children: [jsx(MainMedia, { item: selected }, selected.id), !hideDownload && !isEmbedMediaItem(selected) && (jsx("div", { className: "absolute right-3 top-3", children: jsx("button", { type: "button", onClick: handleDownload, "aria-label": "Download media", className: "inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-md border border-border bg-card text-foreground transition-all hover:border-primary hover:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:border-primary focus-visible:shadow-[0_0_0_4px_rgba(49,122,81,0.10)] focus-visible:outline-none", children: jsx(Download, { className: "h-4 w-4" }) }) }))] })) : (jsx("div", { className: cn('flex items-center justify-center rounded-xl border border-dashed border-border bg-muted/40 text-sm text-muted-foreground', mainAspectClassName), children: emptyText })), visibleItems.length > 1 && (jsx("div", { className: "grid gap-3", style: {
|
|
65807
65962
|
gridTemplateColumns: `repeat(${Math.min(visibleItems.length, thumbsVisible)}, minmax(0, 1fr))`,
|
|
65808
65963
|
}, children: visibleItems.slice(0, thumbsVisible).map((item) => (jsx(Thumbnail, { item: item, isActive: selected?.id === item.id, onSelect: () => setSelected(item) }, item.id))) }))] }));
|
|
65809
65964
|
};
|
|
@@ -65866,7 +66021,7 @@ const navbarIconButtonVariants = cva([
|
|
|
65866
66021
|
});
|
|
65867
66022
|
/** Tiny solid-pill badge ("8") absolutely positioned on the icon button. */
|
|
65868
66023
|
const navbarIndicatorCountVariants = cva([
|
|
65869
|
-
'absolute -top-
|
|
66024
|
+
'absolute -top-2.5 -right-2.5 inline-flex items-center justify-center',
|
|
65870
66025
|
'min-w-4 h-4 px-1 rounded-full ring-2 ring-card',
|
|
65871
66026
|
'text-[10px] font-medium leading-none tabular-nums text-white',
|
|
65872
66027
|
].join(' '), {
|
|
@@ -65953,10 +66108,11 @@ const NavbarTitle = ({ title, items, level = 1, className, ...props }) => {
|
|
|
65953
66108
|
// ─── Right-side actions container ────────────────────────────────────────────
|
|
65954
66109
|
const NavbarActions = ({ gap = 'md', className, children, ...props }) => (jsx("div", { className: cn(navbarActionsVariants({ gap }), className), ...props, children: children }));
|
|
65955
66110
|
// ─── Icon button (with optional dot or count badge) ──────────────────────────
|
|
65956
|
-
const NavbarIconButton = ({ appearance = 'plain', size = 'md', indicator = false, className, children, type = 'button', ...props }) => {
|
|
66111
|
+
const NavbarIconButton = forwardRef(({ appearance = 'plain', size = 'md', indicator = false, className, children, type = 'button', ...props }, ref) => {
|
|
65957
66112
|
const resolved = resolveIndicator(indicator);
|
|
65958
|
-
return (jsxs("button", { type: type, className: cn(navbarIconButtonVariants({ appearance, size }), className), ...props, children: [jsx("span", { "aria-hidden": "true", className: "inline-flex", children: children }), resolved && resolved.count !== null && (jsx("span", { role: "img", "aria-label": navbarA11y.notificationIndicatorLabel, className: cn(navbarIndicatorCountVariants({ tone: resolved.tone })), children: resolved.count })), resolved && resolved.count === null && (jsx("span", { role: "img", "aria-label": navbarA11y.notificationIndicatorLabel, className: cn(navbarIndicatorDotVariants({ tone: resolved.tone })) }))] }));
|
|
65959
|
-
};
|
|
66113
|
+
return (jsxs("button", { ref: ref, type: type, className: cn(navbarIconButtonVariants({ appearance, size }), className), ...props, children: [jsx("span", { "aria-hidden": "true", className: "inline-flex", children: children }), resolved && resolved.count !== null && (jsx("span", { role: "img", "aria-label": navbarA11y.notificationIndicatorLabel, className: cn(navbarIndicatorCountVariants({ tone: resolved.tone })), children: resolved.count })), resolved && resolved.count === null && (jsx("span", { role: "img", "aria-label": navbarA11y.notificationIndicatorLabel, className: cn(navbarIndicatorDotVariants({ tone: resolved.tone })) }))] }));
|
|
66114
|
+
});
|
|
66115
|
+
NavbarIconButton.displayName = 'NavbarIconButton';
|
|
65960
66116
|
// ─── Search input (matches Figma 288×36 muted pill) ──────────────────────────
|
|
65961
66117
|
const NavbarSearch = ({ placeholder = 'Search', value, onChange, onClear, className, containerClassName, ...rest }) => {
|
|
65962
66118
|
const isControlled = value !== undefined;
|
|
@@ -66040,7 +66196,8 @@ const NavLeaf = ({ item, currentPath, onNavigate }) => {
|
|
|
66040
66196
|
const Icon = item.icon;
|
|
66041
66197
|
const active = isPathActive(currentPath, item.path);
|
|
66042
66198
|
const { collapsed, expandSidebar } = useCollapsedSidebar();
|
|
66043
|
-
return (jsxs(SidebarMenuItem, { className: cn(active &&
|
|
66199
|
+
return (jsxs(SidebarMenuItem, { className: cn(active &&
|
|
66200
|
+
'flex items-center gap-1.5 group-data-[collapsible=icon]:block'), children: [active && jsx(ActiveRail, {}), jsxs(SidebarMenuButton, { isActive: active, tooltip: item.label, onClick: () => {
|
|
66044
66201
|
if (collapsed)
|
|
66045
66202
|
expandSidebar();
|
|
66046
66203
|
if (item.path)
|
|
@@ -66090,12 +66247,15 @@ function resolveBreadcrumb(pageMeta, leafOverride) {
|
|
|
66090
66247
|
return crumbs;
|
|
66091
66248
|
return crumbs.map((crumb, index) => index === crumbs.length - 1 ? { ...crumb, label: leafOverride } : crumb);
|
|
66092
66249
|
}
|
|
66093
|
-
const ShellHeader = ({ pageMeta, breadcrumbLeafOverride, user, profileMenuItems, onLogout, showThemeToggle, isDark, onToggleTheme, showNotifications, notificationsIndicator, onNotificationsClick, headerActionsSlot, }) => {
|
|
66250
|
+
const ShellHeader = ({ pageMeta, breadcrumbLeafOverride, user, profileMenuItems, onLogout, showThemeToggle, isDark, onToggleTheme, showNotifications, notificationsIndicator, onNotificationsClick, notificationsPanel, notificationsOpen, onNotificationsOpenChange, headerActionsSlot, }) => {
|
|
66094
66251
|
const { isMobile } = useSidebar();
|
|
66095
66252
|
const breadcrumb = resolveBreadcrumb(pageMeta, breadcrumbLeafOverride);
|
|
66096
|
-
return (jsxs(Navbar, { "aria-label": "Top navigation", children: [jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [isMobile && jsx(SidebarTrigger, {}), breadcrumb ? (jsx(NavbarTitle, { items: breadcrumb })) : (pageMeta?.title && jsx(NavbarTitle, { title: pageMeta.title }))] }), jsxs(NavbarActions, { gap: "lg", children: [headerActionsSlot, showThemeToggle && (jsx(NavbarIconButton, { "aria-label": isDark ? 'Switch to light theme' : 'Switch to dark theme', size: "md", onClick: onToggleTheme, children: isDark ? jsx(Sun, { size: 20 }) : jsx(Moon, { size: 20 }) })), showNotifications &&
|
|
66253
|
+
return (jsxs(Navbar, { "aria-label": "Top navigation", children: [jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [isMobile && jsx(SidebarTrigger, {}), breadcrumb ? (jsx(NavbarTitle, { items: breadcrumb })) : (pageMeta?.title && jsx(NavbarTitle, { title: pageMeta.title }))] }), jsxs(NavbarActions, { gap: "lg", children: [headerActionsSlot, showThemeToggle && (jsx(NavbarIconButton, { "aria-label": isDark ? 'Switch to light theme' : 'Switch to dark theme', size: "md", onClick: onToggleTheme, children: isDark ? jsx(Sun, { size: 20 }) : jsx(Moon, { size: 20 }) })), showNotifications &&
|
|
66254
|
+
(notificationsPanel ? (jsxs(Popover, { open: notificationsOpen, onOpenChange: onNotificationsOpenChange, children: [jsx(PopoverTrigger, { asChild: true, children: jsx(NavbarIconButton, { "aria-label": "Notifications", size: "md", indicator: notificationsIndicator || undefined, onClick: onNotificationsClick, children: jsx(Bell, { size: 20 }) }) }), jsx(PopoverContent, { align: "end", sideOffset: 8, className: "w-[min(24rem,calc(100vw-2rem))] p-0", children: notificationsPanel })] })) : (jsx(NavbarIconButton, { "aria-label": "Notifications", size: "md", indicator: notificationsIndicator || undefined, onClick: onNotificationsClick, children: jsx(Bell, { size: 20 }) }))), jsx(ProfileMenu, { user: user, profileMenuItems: profileMenuItems, onLogout: onLogout })] })] }));
|
|
66097
66255
|
};
|
|
66098
|
-
const DashboardShell = ({ brand, navGroups, currentPath, onNavigate, pageMeta, breadcrumbLeafOverride, user, profileMenuItems, onLogout, showThemeToggle, isDark, onToggleTheme, showNotifications, notificationsIndicator, onNotificationsClick, headerActionsSlot, sidebarWidth, children, }) => (jsxs(SidebarProvider, { className: "h-screen min-h-0", style: {
|
|
66256
|
+
const DashboardShell = ({ brand, navGroups, currentPath, onNavigate, pageMeta, breadcrumbLeafOverride, user, profileMenuItems, onLogout, showThemeToggle, isDark, onToggleTheme, showNotifications, notificationsIndicator, onNotificationsClick, notificationsPanel, notificationsOpen, onNotificationsOpenChange, headerActionsSlot, sidebarWidth, children, }) => (jsxs(SidebarProvider, { className: "h-screen min-h-0", style: {
|
|
66257
|
+
'--sidebar-width': sidebarWidth ?? DEFAULT_SIDEBAR_WIDTH,
|
|
66258
|
+
}, children: [jsx(ShellSidebar, { brand: brand, navGroups: navGroups, currentPath: currentPath, onNavigate: onNavigate }), jsxs(SidebarInset, { className: "flex h-screen flex-col overflow-hidden bg-background", children: [jsx(ShellHeader, { pageMeta: pageMeta, breadcrumbLeafOverride: breadcrumbLeafOverride, user: user, profileMenuItems: profileMenuItems, onLogout: onLogout, showThemeToggle: showThemeToggle, isDark: isDark, onToggleTheme: onToggleTheme, showNotifications: showNotifications, notificationsIndicator: notificationsIndicator, onNotificationsClick: onNotificationsClick, notificationsPanel: notificationsPanel, notificationsOpen: notificationsOpen, onNotificationsOpenChange: onNotificationsOpenChange, headerActionsSlot: headerActionsSlot }), jsx("main", { className: "flex min-h-0 flex-1 flex-col overflow-y-auto", children: children })] })] }));
|
|
66099
66259
|
|
|
66100
66260
|
function CreateFormPageHeader({ title, onBack, backLabel = 'Go back', }) {
|
|
66101
66261
|
return (jsxs("div", { className: "mb-4 flex items-center justify-between gap-4", children: [jsx("h1", { className: "min-w-0 text-xl font-semibold leading-7 text-foreground", children: title }), jsx("div", { className: "flex shrink-0 items-center gap-2", children: jsxs(Button$1, { type: "button", variant: "ghost", onClick: onBack, className: "h-8 shrink-0 gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium text-secondary-foreground hover:text-secondary-foreground", children: [jsx(ChevronLeft, { className: "h-4 w-4", "aria-hidden": true }), backLabel] }) })] }));
|
|
@@ -68106,5 +68266,5 @@ var RichTextAreaImpl = /*#__PURE__*/Object.freeze({
|
|
|
68106
68266
|
RichTextarea: RichTextarea
|
|
68107
68267
|
});
|
|
68108
68268
|
|
|
68109
|
-
export { ActionBadge, ActionButtonWithTooltip, AdvancedSearchDrawer, Alert, ApiComboBox, AppSidebar, AuditEntryCard, AuditHistoryPanel, AuditTimeline, AuditTimelineShimmer, Badge, BadgeType, BusinessContactStatusFilter, Button, CUSTOMER_AUDIT_CONFIG, CertificateRowList, ChangePill, Collapsible, CollapsibleCard, CollapsibleContent, CollapsibleTrigger, ConfirmDialog, ContactTypeFilter, CopyButton, CreateFormPageHeader, CreateFormPageShell, CurrencyDisplayTabs, CurrencyInput, CurrencyToggle, CustomCombobox, CustomTable, CustomizeColumnsDrawer, DIAMOND_AUDIT_CONFIG, DashboardShell, DataEditableTable, DataTable, DateInput, DetailChip, DetailPageLayout, DetailPageSkeleton, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EntityHeader, Field, FieldSkeleton, FileUploader, FilterMultiSelect, FilterSelect, FormSectionCard, FormSectionCardSkeleton, GEM_AUDIT_CONFIG, HistoryEntryCard, HistoryTimeline, HistoryTimelineShimmer, INVOICE_AUDIT_CONFIG, IconButton, IdHyperlinkText, InfoBanner, InventoryComboBox, InventoryItemCard, InventoryItemRow, InvoiceComboBox, KYCStatusFilter, KeyValueGrid, LAYOUT_AUDIT_CONFIG, LabeledToggle, MEMO_IN_AUDIT_CONFIG, MEMO_OUT_AUDIT_CONFIG, MediaGallery, MemoInComboBox, MetricCard, MetricRow, MetricTile, Modal, MoreInfoPanel, MoreInfoTrigger, Navbar, NavbarActions, NavbarAvatar, NavbarIconButton, NavbarSearch, NavbarTitle, NumberInput, NumberedStepCard, OtpInput, OwnershipFilter, OwnershipSplitCard, PROFORMA_AUDIT_CONFIG, PageHeader, PageTabs, Pagination, PaginationSelect, PartnerShareCard, PriceInput, Protected, PurchaseOrderComboBox, QUOTATION_AUDIT_CONFIG, RadioCardGroup, ReadMoreText, RefreshButton, RichTextarea$1 as RichTextarea, SEARCHABLE_SELECT_PAGE_SIZE, SafeImage, SearchBox, SearchInput, SearchableSelect, SectionCard, SectionIcon, SegmentedControl, ShareDialog, ShareMenu, ShimmerTable, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, SlideOut, SlideOutClose, SlideOutContent, SlideOutDescription, SlideOutHeader, SlideOutOverlay, SlideOutPortal, SlideOutTitle, SlideOutTrigger, Slider, SpecList, Spinner, SquareSkeleton, StatusBadge$1 as StatusBadge, StatusFilter, Stepper, StockTypeFilter, TablePagination, TableSkeleton, Tabs, TabsContent, TabsList, TabsTrigger, TagsInput, TextHyperlink, TimePicker, ToggleSwitch, TruncateTooltip, WarehouseComboBox, WarehouseFilter, ZoomSplitViewer, badgeVariants, buildBulkShareTitle, buildInventoryPublicUrl, buildInventoryRowProps, buildInventoryShareTitle, buildWhatsappUrl, buttonVariants, cn, createVideoMediaItem, dropdownMenuItemDestructiveClass, formatFileSize, generateActionDescription, generateTitle, getBadgeTypeForStatus, getChangePills, getInitials, iconButtonVariants, isPathActive, notify, releaseStaleOverlayBodyLock, renderBadge, useAuditShowMore, useBadge, useButton, useDropdownMenu, useNavbar, useSidebar, videoThumbnailSrc, watchOverlayBodyLock };
|
|
68269
|
+
export { ActionBadge, ActionButtonWithTooltip, AdvancedSearchDrawer, Alert, ApiComboBox, AppSidebar, AuditEntryCard, AuditHistoryPanel, AuditTimeline, AuditTimelineShimmer, Badge, BadgeType, BusinessContactStatusFilter, Button, CUSTOMER_AUDIT_CONFIG, CertificateRowList, ChangePill, Collapsible, CollapsibleCard, CollapsibleContent, CollapsibleTrigger, ConfirmDialog, ContactTypeFilter, CopyButton, CreateFormPageHeader, CreateFormPageShell, CurrencyDisplayTabs, CurrencyInput, CurrencyToggle, CustomCombobox, CustomTable, CustomizeColumnsDrawer, DIAMOND_AUDIT_CONFIG, DashboardShell, DataEditableTable, DataTable, DateInput, DetailChip, DetailPageLayout, DetailPageSkeleton, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EntityHeader, Field, FieldSkeleton, FileUploader, FilterMultiSelect, FilterSelect, FormSectionCard, FormSectionCardSkeleton, GEM_AUDIT_CONFIG, HistoryEntryCard, HistoryTimeline, HistoryTimelineShimmer, INVOICE_AUDIT_CONFIG, IconButton, IdHyperlinkText, InAppNotificationCard, InAppNotificationsPanel, InfoBanner, InventoryComboBox, InventoryItemCard, InventoryItemRow, InvoiceComboBox, KYCStatusFilter, KeyValueGrid, LAYOUT_AUDIT_CONFIG, LabeledToggle, MEMO_IN_AUDIT_CONFIG, MEMO_OUT_AUDIT_CONFIG, MediaGallery, MemoInComboBox, MetricCard, MetricRow, MetricTile, Modal, MoreInfoPanel, MoreInfoTrigger, Navbar, NavbarActions, NavbarAvatar, NavbarIconButton, NavbarSearch, NavbarTitle, NumberInput, NumberedStepCard, OtpInput, OwnershipFilter, OwnershipSplitCard, PROFORMA_AUDIT_CONFIG, PageHeader, PageTabs, Pagination, PaginationSelect, PartnerShareCard, PriceInput, Protected, PurchaseOrderComboBox, QUOTATION_AUDIT_CONFIG, RadioCardGroup, ReadMoreText, RefreshButton, RichTextarea$1 as RichTextarea, SEARCHABLE_SELECT_PAGE_SIZE, SafeImage, SearchBox, SearchInput, SearchableSelect, SectionCard, SectionIcon, SegmentedControl, ShareDialog, ShareMenu, ShimmerTable, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarInset, SidebarMenu, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, SlideOut, SlideOutClose, SlideOutContent, SlideOutDescription, SlideOutHeader, SlideOutOverlay, SlideOutPortal, SlideOutTitle, SlideOutTrigger, Slider, SpecList, Spinner, SquareSkeleton, StatusBadge$1 as StatusBadge, StatusFilter, Stepper, StockTypeFilter, TablePagination, TableSkeleton, Tabs, TabsContent, TabsList, TabsTrigger, TagsInput, TextHyperlink, TimePicker, ToggleSwitch, TruncateTooltip, WarehouseComboBox, WarehouseFilter, ZoomSplitViewer, badgeVariants, buildBulkShareTitle, buildInventoryPublicUrl, buildInventoryRowProps, buildInventoryShareTitle, buildWhatsappUrl, buttonVariants, cn, createVideoMediaItem, dropdownMenuItemDestructiveClass, formatFileSize, generateActionDescription, generateTitle, getBadgeTypeForStatus, getChangePills, getInitials, iconButtonVariants, inAppNotificationCardA11y, inAppNotificationsPanelA11y, isPathActive, notify, releaseStaleOverlayBodyLock, renderBadge, useAuditShowMore, useBadge, useButton, useDropdownMenu, useInAppNotificationsPanel, useNavbar, useSidebar, videoThumbnailSrc, watchOverlayBodyLock };
|
|
68110
68270
|
//# sourceMappingURL=index.esm.js.map
|