@flikk/ui 1.0.0-beta.12 → 1.0.0-beta.14
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/ai/PromptInput/PromptInput.js +1 -1
- package/dist/components/ai/PromptInput/VoiceRecorder.js +1 -1
- package/dist/components/ai/PromptSuggestions/PromptSuggestion.theme.js +1 -1
- package/dist/components/ai/StreamingResponse/StreamingResponse.types.d.ts +7 -7
- package/dist/components/charts/FunnelChart/FunnelChart.js +2 -2
- package/dist/components/core/Accordion/Accordion.types.d.ts +1 -7
- package/dist/components/core/Accordion/AccordionTrigger.js +4 -6
- package/dist/components/core/Alert/Alert.types.d.ts +1 -1
- package/dist/components/core/Avatar/Avatar.js +22 -18
- package/dist/components/core/Avatar/Avatar.theme.js +1 -1
- package/dist/components/core/Avatar/Avatar.types.d.ts +9 -8
- package/dist/components/core/AvatarGroup/AvatarGroup.js +2 -2
- package/dist/components/core/Badge/Badge.js +10 -8
- package/dist/components/core/Badge/Badge.theme.js +14 -7
- package/dist/components/core/Badge/Badge.types.d.ts +3 -3
- package/dist/components/core/Button/Button.ripple.js +1 -1
- package/dist/components/core/Button/Button.theme.d.ts +1 -1
- package/dist/components/core/Button/Button.theme.js +5 -5
- package/dist/components/core/Button/Button.types.d.ts +1 -1
- package/dist/components/core/Calendar/CalendarEvent/CalendarEvent.types.d.ts +5 -6
- package/dist/components/core/Calendar/CalendarMini/CalendarMini.js +2 -2
- package/dist/components/core/Drawer/DrawerHeader.js +1 -1
- package/dist/components/core/FileTypeIcon/FileTypeIcon.d.ts +3 -0
- package/dist/components/core/FileTypeIcon/FileTypeIcon.js +33 -0
- package/dist/components/core/FileTypeIcon/FileTypeIcon.theme.d.ts +2 -0
- package/dist/components/core/FileTypeIcon/FileTypeIcon.theme.js +12 -0
- package/dist/components/core/FileTypeIcon/FileTypeIcon.types.d.ts +19 -0
- package/dist/components/core/FileTypeIcon/fileTypes.d.ts +7 -0
- package/dist/components/core/FileTypeIcon/fileTypes.js +30 -0
- package/dist/components/core/FileTypeIcon/index.d.ts +2 -0
- package/dist/components/core/Link/Link.js +1 -1
- package/dist/components/core/MenuItem/MenuItem.theme.js +1 -1
- package/dist/components/core/Message/Message.js +1 -1
- package/dist/components/core/Message/Message.theme.js +2 -2
- package/dist/components/core/Message/Message.types.d.ts +6 -6
- package/dist/components/core/Message/MessageAvatar.d.ts +2 -2
- package/dist/components/core/Message/MessageAvatar.js +3 -3
- package/dist/components/core/Modal/ModalHeader.js +1 -1
- package/dist/components/core/NavItem/NavItem.js +100 -52
- package/dist/components/core/NavItem/NavItem.theme.js +6 -3
- package/dist/components/core/NavItem/NavItem.types.d.ts +44 -30
- package/dist/components/core/NavItem/index.d.ts +1 -1
- package/dist/components/core/Pill/Pill.theme.js +1 -1
- package/dist/components/core/Popover/PopoverBody.js +19 -8
- package/dist/components/core/Sidebar/Sidebar.d.ts +11 -1
- package/dist/components/core/Sidebar/Sidebar.js +49 -16
- package/dist/components/core/Sidebar/Sidebar.theme.js +9 -7
- package/dist/components/core/Sidebar/Sidebar.types.d.ts +57 -0
- package/dist/components/core/Sidebar/SidebarContent.js +3 -1
- package/dist/components/core/Sidebar/SidebarContext.d.ts +14 -0
- package/dist/components/core/Sidebar/SidebarContext.js +63 -11
- package/dist/components/core/Sidebar/SidebarFooter.js +3 -1
- package/dist/components/core/Sidebar/SidebarHeader.js +6 -2
- package/dist/components/core/Sidebar/SidebarMobileTrigger.d.ts +3 -0
- package/dist/components/core/Sidebar/SidebarMobileTrigger.js +28 -0
- package/dist/components/core/Sidebar/SidebarNav.js +3 -2
- package/dist/components/core/Sidebar/SidebarNavGroup.js +4 -2
- package/dist/components/core/Sidebar/SidebarToggle.js +1 -1
- package/dist/components/core/Sidebar/SidebarUserProfile.d.ts +3 -0
- package/dist/components/core/Sidebar/SidebarUserProfile.js +35 -0
- package/dist/components/core/Sidebar/index.d.ts +3 -1
- package/dist/components/core/Tabs/Tabs.theme.d.ts +1 -1
- package/dist/components/core/Tabs/Tabs.theme.js +3 -3
- package/dist/components/core/Tag/Tag.d.ts +1 -1
- package/dist/components/core/Tag/Tag.js +2 -2
- package/dist/components/core/Tag/Tag.types.d.ts +1 -1
- package/dist/components/core/index.d.ts +1 -1
- package/dist/components/core/index.js +3 -1
- package/dist/components/data-display/Feed/Feed.animations.d.ts +40 -0
- package/dist/components/data-display/Feed/Feed.animations.js +26 -0
- package/dist/components/data-display/Feed/Feed.d.ts +5 -1
- package/dist/components/data-display/Feed/Feed.js +87 -60
- package/dist/components/data-display/Feed/Feed.theme.js +11 -13
- package/dist/components/data-display/Feed/Feed.types.d.ts +35 -34
- package/dist/components/data-display/Feed/index.d.ts +1 -1
- package/dist/components/data-display/GanttChart/GanttTaskBar.js +11 -9
- package/dist/components/data-display/GanttChart/GanttToolbar.js +1 -1
- package/dist/components/data-display/Timeline/TimelineMarker.js +2 -2
- package/dist/components/effects/3d/index.d.ts +1 -1
- package/dist/components/effects/AIOrb/AIOrb.d.ts +1 -0
- package/dist/components/effects/AIOrb/AIOrb.js +3 -2
- package/dist/components/effects/AIOrb/AIOrb.types.d.ts +1 -0
- package/dist/components/effects/AIOrb/hooks/index.d.ts +2 -0
- package/dist/components/effects/AIOrb/hooks/useOrbState.d.ts +20 -0
- package/dist/components/effects/AIOrb/hooks/useOrbState.js +27 -0
- package/dist/components/effects/AIOrb/index.d.ts +2 -2
- package/dist/components/effects/AIOrb/variants/Aura/Aura.d.ts +3 -0
- package/dist/components/effects/AIOrb/variants/Aura/Aura.js +75 -0
- package/dist/components/effects/AIOrb/variants/Aura/Aura.shaders.d.ts +28 -0
- package/dist/components/effects/AIOrb/variants/Aura/Aura.shaders.js +191 -0
- package/dist/components/effects/AIOrb/variants/Aura/Aura.types.d.ts +53 -0
- package/dist/components/effects/AIOrb/variants/Aura/ShaderCanvas.d.ts +17 -0
- package/dist/components/effects/AIOrb/variants/Aura/ShaderCanvas.js +149 -0
- package/dist/components/effects/AIOrb/variants/Aura/index.d.ts +2 -0
- package/dist/components/effects/AIOrb/variants/DotSphere/DotSphere.js +38 -7
- package/dist/components/effects/AIOrb/variants/DotSphere/DotSphere.types.d.ts +6 -0
- package/dist/components/effects/AIOrb/variants/Liquid/Liquid.js +34 -8
- package/dist/components/effects/AIOrb/variants/Liquid/Liquid.types.d.ts +6 -0
- package/dist/components/effects/AIOrb/variants/index.d.ts +2 -0
- package/dist/components/effects/CustomCursor/CustomCursor.d.ts +2 -2
- package/dist/components/effects/CustomCursor/CustomCursor.js +50 -47
- package/dist/components/effects/GlassSurface/GlassSurface.js +24 -12
- package/dist/components/effects/GlassSurface/GlassSurface.types.d.ts +8 -0
- package/dist/components/forms/Mention/Mention.js +2 -2
- package/dist/components/forms/RichTextEditor/RichTextEditor.js +10 -10
- package/dist/index.js +3 -1
- package/dist/styles.css +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/paletteGenerator.d.ts +46 -0
- package/package.json +1 -1
- package/src/global.scss +1 -0
- package/src/styles/theme.css +50 -54
- package/dist/components/core/Loader/Loader.d.ts +0 -24
- package/dist/components/core/Loader/Loader.js +0 -57
- package/dist/components/core/Loader/Loader.theme.d.ts +0 -27
- package/dist/components/core/Loader/Loader.theme.js +0 -60
- package/dist/components/core/Loader/Loader.types.d.ts +0 -71
- package/dist/components/core/Loader/index.d.ts +0 -2
|
@@ -512,7 +512,7 @@ className, textareaClassName, footerClassName, theme = {},
|
|
|
512
512
|
return (jsx(Button, { iconOnly: true, className: cn(mergedTheme.submitButtonStyle, extraClassName), size: buttonSize, variant: buttonVariant, color: buttonColor, onClick: handleSubmit, disabled: !canSubmit, state: isLoading ? "loading" : "default", "aria-label": submitButtonLabel, title: submitShortcut ? `Submit (${submitShortcut})` : undefined, showReflection: buttonVariant === "filled" ? false : undefined, children: jsx(AnimatePresence, { mode: "wait", initial: false, children: jsx(motion.span, { variants: iconSwapVariants, initial: "initial", animate: "animate", exit: "exit", className: "flex items-center justify-center", children: submitButtonIcon }, "submit") }) }));
|
|
513
513
|
};
|
|
514
514
|
// ========== Render ==========
|
|
515
|
-
return (jsxs("div", { className: cn("
|
|
515
|
+
return (jsxs("div", { className: cn("w-full mx-auto", className), ...props, children: [jsx("input", { ref: fileInputRef, type: "file", accept: acceptedFileTypes.join(","), multiple: true, onChange: (e) => {
|
|
516
516
|
if (e.target.files)
|
|
517
517
|
processFiles(e.target.files);
|
|
518
518
|
e.target.value = "";
|
|
@@ -170,7 +170,7 @@ const VoiceRecorder = ({ onComplete, onCancel, maxDuration, className, }) => {
|
|
|
170
170
|
setRecordingState("recording");
|
|
171
171
|
}
|
|
172
172
|
}, [recordingState, clearTimer, startTimer]);
|
|
173
|
-
return (jsxs("div", { className: cn("flex items-center justify-between w-full", className), children: [jsx(Button, { variant: "
|
|
173
|
+
return (jsxs("div", { className: cn("flex items-center justify-between w-full", className), children: [jsx(Button, { variant: "soft", color: "neutral", size: "sm", className: "rounded-full", onClick: handleCancel, "aria-label": "Cancel recording", children: "Cancel" }), jsxs("div", { className: "flex items-center gap-2.5", children: [jsx(motion.div, { className: "size-2.5 rounded-full bg-[var(--color-danger)]", animate: recordingState === "recording"
|
|
174
174
|
? { opacity: [1, 0.3, 1] }
|
|
175
175
|
: { opacity: 0.5 }, transition: recordingState === "recording"
|
|
176
176
|
? { duration: 1.2, repeat: Infinity, ease: "easeInOut" }
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const promptSuggestionTheme = {
|
|
2
|
-
baseStyle: "inline-flex items-center gap-2 py-
|
|
2
|
+
baseStyle: "inline-flex items-center gap-2 py-1 px-3 rounded-full " +
|
|
3
3
|
"bg-white dark:bg-[var(--color-background)] " +
|
|
4
4
|
"border border-[var(--color-border)] " +
|
|
5
5
|
"text-base font-medium text-[var(--color-text-primary)] " +
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
* StreamingResponse Component Types
|
|
3
3
|
* Type definitions for the StreamingResponse component
|
|
4
4
|
*/
|
|
5
|
-
import type { ReactNode } from
|
|
6
|
-
import type { SSEFormat, SSEParser } from
|
|
7
|
-
import type { StreamingError, RetryConfig } from
|
|
8
|
-
import type { MessageRole } from
|
|
5
|
+
import type { ReactNode } from "react";
|
|
6
|
+
import type { SSEFormat, SSEParser } from "../../../utils/sseFormatParsers";
|
|
7
|
+
import type { StreamingError, RetryConfig } from "../../../utils";
|
|
8
|
+
import type { MessageRole } from "../../core/Message";
|
|
9
9
|
/**
|
|
10
10
|
* Avatar configuration for Message component
|
|
11
11
|
*/
|
|
12
12
|
export interface MessageAvatarProps {
|
|
13
13
|
src?: string;
|
|
14
|
-
|
|
14
|
+
name: string;
|
|
15
15
|
fallback?: ReactNode;
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
@@ -21,7 +21,7 @@ export interface MarkdownOptions {
|
|
|
21
21
|
/** Allow HTML in markdown (default: false) */
|
|
22
22
|
allowHtml?: boolean;
|
|
23
23
|
/** Syntax highlighting theme (default: 'light') */
|
|
24
|
-
syntaxTheme?:
|
|
24
|
+
syntaxTheme?: "light" | "dark";
|
|
25
25
|
/** Custom code block renderer */
|
|
26
26
|
renderCodeBlock?: (code: string, language: string) => ReactNode;
|
|
27
27
|
}
|
|
@@ -32,7 +32,7 @@ export interface StreamingResponseProps {
|
|
|
32
32
|
/** The SSE endpoint URL */
|
|
33
33
|
url: string;
|
|
34
34
|
/** HTTP method (default: 'POST') */
|
|
35
|
-
method?:
|
|
35
|
+
method?: "GET" | "POST";
|
|
36
36
|
/** Request headers */
|
|
37
37
|
headers?: Record<string, string>;
|
|
38
38
|
/** Request body (for POST requests) */
|
|
@@ -430,7 +430,7 @@ const FunnelChart = ({ data, height = 400, width = 600, showPercentages = true,
|
|
|
430
430
|
animate: "visible",
|
|
431
431
|
custom: index,
|
|
432
432
|
}
|
|
433
|
-
: {}), children: jsxs(Badge, { color: isGoodConversion ? "success" : "warning", variant: "
|
|
433
|
+
: {}), children: jsxs(Badge, { color: isGoodConversion ? "success" : "warning", variant: "soft", size: "sm", pill: true, children: ["\u2193 ", stage.conversionRate.toFixed(1), "%"] }) }, `conversion-${stage.name}`));
|
|
434
434
|
}), orientation === "vertical" &&
|
|
435
435
|
showConversionRate &&
|
|
436
436
|
stages.map((stage, index) => {
|
|
@@ -448,7 +448,7 @@ const FunnelChart = ({ data, height = 400, width = 600, showPercentages = true,
|
|
|
448
448
|
animate: "visible",
|
|
449
449
|
custom: index,
|
|
450
450
|
}
|
|
451
|
-
: {}), children: jsxs(Badge, { color: isGoodConversion ? "success" : "warning", variant: "
|
|
451
|
+
: {}), children: jsxs(Badge, { color: isGoodConversion ? "success" : "warning", variant: "soft", size: "sm", pill: true, children: [stage.conversionRate.toFixed(0), "%"] }) }, `conversion-${stage.name}`));
|
|
452
452
|
}), showSummary && summaryPosition !== "none" && stages.length > 1 && (jsxs(motion.div, { className: cn("absolute bg-[var(--color-background)] rounded-lg shadow-sm border border-[var(--color-border)] px-3 py-2 pointer-events-none", getSummaryPositionClasses(summaryPosition)), ...(animate
|
|
453
453
|
? {
|
|
454
454
|
variants: summaryVariants,
|
|
@@ -92,7 +92,7 @@ export interface AccordionTriggerProps extends React.HTMLAttributes<HTMLButtonEl
|
|
|
92
92
|
className?: string;
|
|
93
93
|
/**
|
|
94
94
|
* Override the default indicator (chevron) icon.
|
|
95
|
-
* Set to `null` to hide it entirely
|
|
95
|
+
* Set to `null` to hide it entirely.
|
|
96
96
|
*/
|
|
97
97
|
chevron?: React.ReactNode | null;
|
|
98
98
|
/**
|
|
@@ -108,12 +108,6 @@ export interface AccordionTriggerProps extends React.HTMLAttributes<HTMLButtonEl
|
|
|
108
108
|
* @default "right"
|
|
109
109
|
*/
|
|
110
110
|
chevronPosition?: "left" | "right";
|
|
111
|
-
/**
|
|
112
|
-
* Set to `false` to hide the chevron icon entirely.
|
|
113
|
-
* Equivalent to passing `chevron={null}`.
|
|
114
|
-
* @default true
|
|
115
|
-
*/
|
|
116
|
-
showChevron?: boolean;
|
|
117
111
|
/**
|
|
118
112
|
* @deprecated Use `chevronRotation` instead.
|
|
119
113
|
*/
|
|
@@ -7,14 +7,14 @@ import { motion } from 'motion/react';
|
|
|
7
7
|
import { PlusIcon } from '@heroicons/react/24/outline';
|
|
8
8
|
import { createTriggerIconVariants } from './Accordion.animations.js';
|
|
9
9
|
|
|
10
|
-
const AccordionTrigger = React__default.forwardRef(({ children, className, chevron, chevronRotation, iconRotation, chevronPosition = "right",
|
|
10
|
+
const AccordionTrigger = React__default.forwardRef(({ children, className, chevron, chevronRotation, iconRotation, chevronPosition = "right", ...props }, ref) => {
|
|
11
11
|
var _a;
|
|
12
12
|
const { theme } = useAccordionContext();
|
|
13
13
|
const { isOpen, toggle, triggerId, contentId } = useAccordionItemContext();
|
|
14
14
|
const resolvedChevronRotation = (_a = chevronRotation !== null && chevronRotation !== void 0 ? chevronRotation : iconRotation) !== null && _a !== void 0 ? _a : 45;
|
|
15
|
-
// Resolve the indicator icon
|
|
15
|
+
// Resolve the indicator icon
|
|
16
16
|
const defaultChevronIcon = jsx(PlusIcon, { className: "size-4", strokeWidth: 2 });
|
|
17
|
-
const resolvedChevron =
|
|
17
|
+
const resolvedChevron = chevron === null
|
|
18
18
|
? null
|
|
19
19
|
: chevron !== undefined
|
|
20
20
|
? chevron
|
|
@@ -22,9 +22,7 @@ const AccordionTrigger = React__default.forwardRef(({ children, className, chevr
|
|
|
22
22
|
? null // rendered in the left slot instead
|
|
23
23
|
: defaultChevronIcon;
|
|
24
24
|
// When chevronPosition="left", render the default animated chevron before children
|
|
25
|
-
const useDefaultOnLeft =
|
|
26
|
-
? false
|
|
27
|
-
: showChevron && chevronPosition === "left" && chevron === undefined;
|
|
25
|
+
const useDefaultOnLeft = chevron !== null && chevronPosition === "left" && chevron === undefined;
|
|
28
26
|
const animatedChevron = (rotation, extraClass) => (jsx(motion.div, { initial: false, animate: isOpen ? "open" : "closed", variants: createTriggerIconVariants(rotation), className: cn("flex items-center justify-center shrink-0", extraClass), children: defaultChevronIcon }));
|
|
29
27
|
return (jsxs("button", { ref: ref, type: "button", id: triggerId, className: cn(theme === null || theme === void 0 ? void 0 : theme.triggerStyle, className), "aria-expanded": isOpen, "aria-controls": contentId, "data-state": isOpen ? "open" : "closed", onClick: toggle, ...props, children: [useDefaultOnLeft && animatedChevron(resolvedChevronRotation), children, resolvedChevron && (jsx(motion.div, { initial: false, animate: isOpen ? "open" : "closed", variants: createTriggerIconVariants(resolvedChevronRotation), className: "flex items-center justify-center shrink-0 ml-auto", children: resolvedChevron }))] }));
|
|
30
28
|
});
|
|
@@ -45,7 +45,7 @@ export interface AlertProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"
|
|
|
45
45
|
showIcon?: boolean;
|
|
46
46
|
/**
|
|
47
47
|
* Avatar to display (takes precedence over icons)
|
|
48
|
-
* Example: avatar={<Avatar src="..."
|
|
48
|
+
* Example: avatar={<Avatar src="..." name="User name" size="md" />}
|
|
49
49
|
*/
|
|
50
50
|
avatar?: ReactNode;
|
|
51
51
|
/**
|
|
@@ -4,12 +4,14 @@ import { cn } from '../../../utils/cn.js';
|
|
|
4
4
|
import { avatarTheme } from './Avatar.theme.js';
|
|
5
5
|
import { Tooltip } from '../Tooltip/Tooltip.js';
|
|
6
6
|
import '../Tooltip/Tooltip.animations.js';
|
|
7
|
+
import { UserIcon } from '@heroicons/react/24/solid';
|
|
7
8
|
|
|
8
|
-
const Avatar = React__default.forwardRef(({ src,
|
|
9
|
-
size = "md", status = "none", fallback, className, role, lazyLoad = true, retryCount = 0, retryDelay = 1000, contextualLabel, groupPosition, showTooltip = false, ...props }, ref) => {
|
|
9
|
+
const Avatar = React__default.forwardRef(({ src, name, size = "md", status = "none", fallback, className, role, lazyLoad = true, retryCount = 0, retryDelay = 1000, contextualLabel, groupPosition, showTooltip = false, initialsCount = 2, ...props }, ref) => {
|
|
10
10
|
const [imageError, setImageError] = useState(false);
|
|
11
11
|
const [retries, setRetries] = useState(0);
|
|
12
12
|
const retryTimerRef = useRef(null);
|
|
13
|
+
// Normalize null to undefined for internal use
|
|
14
|
+
const resolvedName = name !== null && name !== void 0 ? name : undefined;
|
|
13
15
|
// Clear timeout on unmount to prevent memory leaks
|
|
14
16
|
useEffect(() => {
|
|
15
17
|
return () => {
|
|
@@ -43,21 +45,23 @@ size = "md", status = "none", fallback, className, role, lazyLoad = true, retryC
|
|
|
43
45
|
}, [retries, retryCount, retryDelay]);
|
|
44
46
|
// Handle fallback content
|
|
45
47
|
const getFallbackContent = () => {
|
|
48
|
+
// 1. Explicit fallback always wins
|
|
46
49
|
if (fallback) {
|
|
47
50
|
return fallback;
|
|
48
51
|
}
|
|
49
|
-
//
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
+
// 2. Generate initials from name
|
|
53
|
+
if (resolvedName) {
|
|
54
|
+
const maxInitials = size === "xs" ? 1 : initialsCount;
|
|
55
|
+
const initials = resolvedName
|
|
56
|
+
.split(" ")
|
|
57
|
+
.map((part) => part[0])
|
|
58
|
+
.slice(0, maxInitials)
|
|
59
|
+
.join("")
|
|
60
|
+
.toUpperCase();
|
|
61
|
+
return jsx("span", { "aria-hidden": "true", children: initials });
|
|
52
62
|
}
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
.split(" ")
|
|
56
|
-
.map((part) => part[0])
|
|
57
|
-
.slice(0, 1)
|
|
58
|
-
.join("")
|
|
59
|
-
.toUpperCase();
|
|
60
|
-
return jsx("span", { "aria-hidden": "true", children: initials });
|
|
63
|
+
// 3. Default placeholder icon
|
|
64
|
+
return jsx(UserIcon, { className: "w-1/2 h-1/2" });
|
|
61
65
|
};
|
|
62
66
|
// Determine status indicator size based on avatar size
|
|
63
67
|
const getStatusSize = () => {
|
|
@@ -78,15 +82,15 @@ size = "md", status = "none", fallback, className, role, lazyLoad = true, retryC
|
|
|
78
82
|
};
|
|
79
83
|
// Create full accessibility label including context if provided
|
|
80
84
|
const accessibilityLabel = contextualLabel
|
|
81
|
-
? `${
|
|
82
|
-
:
|
|
85
|
+
? `${resolvedName !== null && resolvedName !== void 0 ? resolvedName : "Avatar"}${contextualLabel}`
|
|
86
|
+
: (resolvedName !== null && resolvedName !== void 0 ? resolvedName : "Avatar");
|
|
83
87
|
// Determine appropriate ARIA role
|
|
84
88
|
const ariaRole = role || (src ? undefined : "img");
|
|
85
89
|
// Avatar content to potentially wrap in tooltip
|
|
86
|
-
const avatarContent = (jsxs("div", { ref: ref, className: cn("relative inline-flex avatar-wrapper", groupPosition), role: ariaRole === "presentation" ? "presentation" : undefined, "aria-label": ariaRole === "presentation" ? undefined : accessibilityLabel, "data-size": size, "data-status": status, "data-error": imageError ? "true" : "false", ...props, children: [jsx("div", { className: cn(avatarTheme.baseStyle, avatarTheme.sizes[size], className), "aria-hidden": ariaRole === "presentation" ? "true" : undefined, "data-size": size, children: src && !imageError ? (jsx("img", { src: src, alt:
|
|
90
|
+
const avatarContent = (jsxs("div", { ref: ref, className: cn("relative inline-flex avatar-wrapper", groupPosition), role: ariaRole === "presentation" ? "presentation" : undefined, "aria-label": ariaRole === "presentation" ? undefined : accessibilityLabel, "data-size": size, "data-status": status, "data-error": imageError ? "true" : "false", ...props, children: [jsx("div", { className: cn(avatarTheme.baseStyle, avatarTheme.sizes[size], className), "aria-hidden": ariaRole === "presentation" ? "true" : undefined, "data-size": size, children: src && !imageError ? (jsx("img", { src: src, alt: resolvedName !== null && resolvedName !== void 0 ? resolvedName : "Avatar", className: "size-full object-cover object-top", onError: handleImageError, loading: lazyLoad ? "lazy" : undefined, "aria-hidden": ariaRole === "presentation" ? "true" : undefined, "data-loaded": "true" })) : (jsx("div", { className: "avatar-fallback", children: getFallbackContent() })) }), status !== "none" && (jsx("span", { className: cn("absolute rounded-full ring-2 ring-[var(--color-background)]", getStatusSize(), avatarTheme.statuses[status]), "aria-label": `Status: ${status}`, role: "status", "data-status": status }))] }));
|
|
87
91
|
// Conditionally wrap in tooltip
|
|
88
|
-
if (showTooltip &&
|
|
89
|
-
return (jsx(Tooltip, { content:
|
|
92
|
+
if (showTooltip && resolvedName) {
|
|
93
|
+
return (jsx(Tooltip, { content: resolvedName, placement: "top", children: avatarContent }));
|
|
90
94
|
}
|
|
91
95
|
return avatarContent;
|
|
92
96
|
});
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
const avatarTheme = {
|
|
5
5
|
// Base styles for the avatar element
|
|
6
|
-
baseStyle: "relative inline-flex items-center justify-center overflow-hidden bg-neutral-200 text-[var(--color-text-primary)] font-
|
|
6
|
+
baseStyle: "relative inline-flex items-center justify-center overflow-hidden bg-neutral-200 text-[var(--color-text-primary)] font-bold tracking-tighter rounded-[var(--avatar-radius)] border border-[var(--color-border)] transition-all duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-offset-2",
|
|
7
7
|
// Size variants using CSS variables
|
|
8
8
|
sizes: {
|
|
9
9
|
xs: "size-[var(--avatar-size-xs)] text-xs",
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { ReactNode } from
|
|
2
|
-
export type AvatarSize =
|
|
3
|
-
export type AvatarStatus =
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
export type AvatarSize = "xs" | "sm" | "md" | "lg" | "xl";
|
|
3
|
+
export type AvatarStatus = "online" | "offline" | "busy" | "away" | "none";
|
|
4
4
|
export interface AvatarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
5
5
|
/**
|
|
6
6
|
* The source URL for the avatar image
|
|
7
7
|
*/
|
|
8
8
|
src?: string;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* The name of the person or entity represented by the avatar.
|
|
11
|
+
* Used to generate initials for the fallback and as alt text for the image.
|
|
12
|
+
* Accepts `null` for compatibility with nullable data sources.
|
|
13
13
|
*/
|
|
14
|
-
|
|
14
|
+
name?: string | null;
|
|
15
15
|
/**
|
|
16
16
|
* The size of the avatar
|
|
17
17
|
* @default "md"
|
|
@@ -23,7 +23,8 @@ export interface AvatarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
23
23
|
*/
|
|
24
24
|
status?: AvatarStatus;
|
|
25
25
|
/**
|
|
26
|
-
* Fallback content to display when image fails to load or no src is provided
|
|
26
|
+
* Fallback content to display when image fails to load or no src is provided.
|
|
27
|
+
* Overrides the default placeholder icon and auto-generated initials.
|
|
27
28
|
*/
|
|
28
29
|
fallback?: ReactNode;
|
|
29
30
|
/**
|
|
@@ -18,7 +18,7 @@ const AvatarGroup = React__default.forwardRef(({ avatars = [], max = 5, size = "
|
|
|
18
18
|
const directionClass = direction === "row-reverse" ? "flex-row-reverse" : "flex-row";
|
|
19
19
|
const totalPeople = avatars.length;
|
|
20
20
|
const groupDescription = avatars
|
|
21
|
-
.map((avatar) => avatar.
|
|
21
|
+
.map((avatar) => avatar.name || "User")
|
|
22
22
|
.join(", ");
|
|
23
23
|
return {
|
|
24
24
|
visibleAvatars,
|
|
@@ -49,7 +49,7 @@ const AvatarGroup = React__default.forwardRef(({ avatars = [], max = 5, size = "
|
|
|
49
49
|
// Ensure that groupPosition is not passed to avoid conflicts
|
|
50
50
|
groupPosition: undefined }) }, index));
|
|
51
51
|
}), overflowCount > 0 && (jsx("div", { className: cn(spacingClass, enableAnimations &&
|
|
52
|
-
"transition-transform duration-200 hover:scale-110"), "data-overflow-count": overflowCount, children: overflowIndicator ? (overflowIndicator(overflowCount)) : (jsx(Avatar, { size: size,
|
|
52
|
+
"transition-transform duration-200 hover:scale-110"), "data-overflow-count": overflowCount, children: overflowIndicator ? (overflowIndicator(overflowCount)) : (jsx(Avatar, { size: size, name: `+${overflowCount} more`, fallback: jsxs("span", { children: ["+", overflowCount] }), className: avatarGroupTheme.overflowAvatarStyle, role: "img", "aria-label": `+ ${overflowCount} more users` })) }))] }));
|
|
53
53
|
});
|
|
54
54
|
// Set display name for dev tools and Storybook
|
|
55
55
|
AvatarGroup.displayName = "AvatarGroup";
|
|
@@ -90,9 +90,9 @@ const Badge = React__default.memo(React__default.forwardRef(({ children, variant
|
|
|
90
90
|
...(_c = badgeTheme.variantColors) === null || _c === void 0 ? void 0 : _c.outline,
|
|
91
91
|
...(_d = customTheme.variantColors) === null || _d === void 0 ? void 0 : _d.outline,
|
|
92
92
|
},
|
|
93
|
-
|
|
94
|
-
...(_e = badgeTheme.variantColors) === null || _e === void 0 ? void 0 : _e.
|
|
95
|
-
...(_f = customTheme.variantColors) === null || _f === void 0 ? void 0 : _f.
|
|
93
|
+
soft: {
|
|
94
|
+
...(_e = badgeTheme.variantColors) === null || _e === void 0 ? void 0 : _e.soft,
|
|
95
|
+
...(_f = customTheme.variantColors) === null || _f === void 0 ? void 0 : _f.soft,
|
|
96
96
|
},
|
|
97
97
|
},
|
|
98
98
|
sizes: {
|
|
@@ -164,14 +164,16 @@ const Badge = React__default.memo(React__default.forwardRef(({ children, variant
|
|
|
164
164
|
// Apply negative margin for overlap effect (scales with badge size)
|
|
165
165
|
const avatarMargin = pill
|
|
166
166
|
? {
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
xs: "-ml-1",
|
|
168
|
+
sm: "-ml-1.5",
|
|
169
|
+
md: "-ml-1.5",
|
|
169
170
|
}[size]
|
|
170
171
|
: {
|
|
171
|
-
|
|
172
|
-
|
|
172
|
+
xs: "-ml-1",
|
|
173
|
+
sm: "-ml-1.5",
|
|
174
|
+
md: "-ml-1",
|
|
173
175
|
}[size];
|
|
174
|
-
return (jsx(Avatar, { src: avatar.src,
|
|
176
|
+
return (jsx(Avatar, { src: avatar.src, name: avatar.name, fallback: avatar.fallback, initialsCount: avatar.initialsCount, className: cn((_a = theme.avatarSizes) === null || _a === void 0 ? void 0 : _a[size], avatarMargin, "border-0", pill ? "rounded-full" : "rounded-md ring-0") }));
|
|
175
177
|
}
|
|
176
178
|
if (iconStart) {
|
|
177
179
|
return (jsx("span", { className: cn("inline-flex items-center justify-center flex-shrink-0", (_b = theme.iconSizes) === null || _b === void 0 ? void 0 : _b[size]), "aria-hidden": "true", children: iconStart }));
|
|
@@ -6,12 +6,12 @@ import { semanticBgColors } from '../../../utils/colorUtils.js';
|
|
|
6
6
|
*/
|
|
7
7
|
const badgeTheme = {
|
|
8
8
|
// Base styles applied to all badges
|
|
9
|
-
baseStyle: "inline-flex items-center
|
|
9
|
+
baseStyle: "inline-flex items-center align-middle select-none whitespace-nowrap transition-all duration-300 h-fit",
|
|
10
10
|
// Visual style variants (structure only, no colors)
|
|
11
11
|
variants: {
|
|
12
12
|
filled: "",
|
|
13
13
|
outline: "bg-transparent border",
|
|
14
|
-
|
|
14
|
+
soft: "ring-transparent border-0",
|
|
15
15
|
},
|
|
16
16
|
// Color styles organized PER VARIANT
|
|
17
17
|
// This structure enables reliable dark: variants and className overrides
|
|
@@ -45,9 +45,9 @@ const badgeTheme = {
|
|
|
45
45
|
danger: "text-[var(--color-danger)] border-[var(--color-border)] " +
|
|
46
46
|
"dark:text-[var(--color-danger-400)]",
|
|
47
47
|
},
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
neutral: "bg-[var(--color-neutral-200)] text-[var(--color-text-
|
|
48
|
+
// Soft variant - subtle background tints
|
|
49
|
+
soft: {
|
|
50
|
+
neutral: "bg-[var(--color-neutral-200)] text-[var(--color-text-primary)] " +
|
|
51
51
|
"dark:bg-[var(--color-neutral-900)] ",
|
|
52
52
|
primary: "bg-[var(--color-primary-100)] text-[var(--color-primary-700)] " +
|
|
53
53
|
"dark:bg-[var(--color-primary-600)]/30 dark:text-[var(--color-primary-400)]",
|
|
@@ -63,36 +63,43 @@ const badgeTheme = {
|
|
|
63
63
|
},
|
|
64
64
|
// Flat size structure (no nested objects)
|
|
65
65
|
sizes: {
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
xs: "text-xs px-1 py-0 gap-1 font-semibold",
|
|
67
|
+
sm: "text-sm px-1.5 py-0 gap-1 font-semibold",
|
|
68
|
+
md: "text-sm px-2 py-0.25 gap-1 font-semibold",
|
|
68
69
|
},
|
|
69
70
|
// Border radius per size (using CSS variable)
|
|
70
71
|
radiusSizes: {
|
|
72
|
+
xs: "rounded-[calc(var(--badge-radius)*0.5)]",
|
|
71
73
|
sm: "rounded-[calc(var(--badge-radius)*0.75)]",
|
|
72
74
|
md: "rounded-[var(--badge-radius)]",
|
|
73
75
|
},
|
|
74
76
|
// Additional padding for pill shape
|
|
75
77
|
pillSizes: {
|
|
78
|
+
xs: "px-1.5",
|
|
76
79
|
sm: "px-2",
|
|
77
80
|
md: "px-2.5",
|
|
78
81
|
},
|
|
79
82
|
// Icon sizes
|
|
80
83
|
iconSizes: {
|
|
84
|
+
xs: "size-2.5",
|
|
81
85
|
sm: "size-3",
|
|
82
86
|
md: "size-3.5",
|
|
83
87
|
},
|
|
84
88
|
// Avatar sizes (base sizes without negative margin)
|
|
85
89
|
avatarSizes: {
|
|
90
|
+
xs: "size-3.5",
|
|
86
91
|
sm: "size-4",
|
|
87
92
|
md: "size-4",
|
|
88
93
|
},
|
|
89
94
|
// Dismiss button container sizes
|
|
90
95
|
dismissButtonSizes: {
|
|
96
|
+
xs: "size-3",
|
|
91
97
|
sm: "size-3.5",
|
|
92
98
|
md: "size-4",
|
|
93
99
|
},
|
|
94
100
|
// Dismiss icon sizes (inside button)
|
|
95
101
|
dismissIconSizes: {
|
|
102
|
+
xs: "size-2",
|
|
96
103
|
sm: "size-2.5",
|
|
97
104
|
md: "size-3",
|
|
98
105
|
},
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { ReactNode, MouseEvent } from "react";
|
|
2
2
|
import { SemanticColor } from "../../../utils/colorUtils";
|
|
3
|
-
export type BadgeVariant = "filled" | "outline" | "
|
|
3
|
+
export type BadgeVariant = "filled" | "outline" | "soft";
|
|
4
4
|
export type BadgeColor = SemanticColor;
|
|
5
|
-
export type BadgeSize = "sm" | "md";
|
|
5
|
+
export type BadgeSize = "xs" | "sm" | "md";
|
|
6
6
|
/**
|
|
7
7
|
* Theme configuration for Badge component
|
|
8
8
|
*/
|
|
@@ -122,7 +122,7 @@ export interface BadgeProps extends Omit<React.HTMLAttributes<HTMLSpanElement>,
|
|
|
122
122
|
*/
|
|
123
123
|
avatar?: {
|
|
124
124
|
src?: string;
|
|
125
|
-
|
|
125
|
+
name: string;
|
|
126
126
|
fallback?: ReactNode;
|
|
127
127
|
initialsCount?: number;
|
|
128
128
|
};
|
|
@@ -120,7 +120,7 @@ function getRippleColorClass(variant, color) {
|
|
|
120
120
|
if (variant === "filled") {
|
|
121
121
|
return "bg-white/30";
|
|
122
122
|
}
|
|
123
|
-
// For outline/
|
|
123
|
+
// For outline/soft buttons, use color-matched ripple
|
|
124
124
|
switch (color) {
|
|
125
125
|
case "primary":
|
|
126
126
|
return "bg-[var(--color-primary)]/20";
|
|
@@ -9,7 +9,7 @@ export interface ButtonTheme {
|
|
|
9
9
|
variantColors: {
|
|
10
10
|
filled: Record<ButtonColor, string>;
|
|
11
11
|
outline: Record<ButtonColor, string>;
|
|
12
|
-
|
|
12
|
+
soft: Record<ButtonColor, string>;
|
|
13
13
|
link: Record<ButtonColor, string>;
|
|
14
14
|
};
|
|
15
15
|
sizes: Record<ButtonSize, {
|
|
@@ -8,7 +8,7 @@ const buttonTheme = {
|
|
|
8
8
|
variantStyles: {
|
|
9
9
|
filled: "border hover:brightness-[0.9] dark:hover:brightness-[1.15]",
|
|
10
10
|
outline: "bg-transparent border",
|
|
11
|
-
|
|
11
|
+
soft: "border-transparent",
|
|
12
12
|
link: "bg-transparent border-transparent",
|
|
13
13
|
},
|
|
14
14
|
// Color styles organized BY VARIANT for reliable dark: prefixes
|
|
@@ -66,8 +66,8 @@ const buttonTheme = {
|
|
|
66
66
|
"dark:text-[var(--color-danger-300)] dark:border-[var(--color-danger-400)] " +
|
|
67
67
|
"dark:hover:bg-[var(--color-danger-900)]/30",
|
|
68
68
|
},
|
|
69
|
-
//
|
|
70
|
-
|
|
69
|
+
// Soft variant - subtle background tints
|
|
70
|
+
soft: {
|
|
71
71
|
neutral: "text-[var(--color-text-primary)] bg-[var(--color-neutral-100)] " +
|
|
72
72
|
"hover:bg-[var(--color-neutral-200)] " +
|
|
73
73
|
"focus-visible:outline-[var(--color-text-secondary)] " +
|
|
@@ -124,9 +124,9 @@ const buttonTheme = {
|
|
|
124
124
|
// Size variants
|
|
125
125
|
sizes: {
|
|
126
126
|
sm: {
|
|
127
|
-
default: "font-semibold min-h-[var(--button-min-h-sm)] px-[var(--button-px-sm)] py-[var(--button-py-sm)] text-
|
|
127
|
+
default: "font-semibold min-h-[var(--button-min-h-sm)] px-[var(--button-px-sm)] py-[var(--button-py-sm)] text-sm",
|
|
128
128
|
iconOnly: "size-[var(--button-icon-size-sm)] p-[var(--button-icon-p-sm)]",
|
|
129
|
-
link: "font-semibold p-0 text-
|
|
129
|
+
link: "font-semibold p-0 text-sm h-fit",
|
|
130
130
|
},
|
|
131
131
|
md: {
|
|
132
132
|
default: "font-semibold min-h-[var(--button-min-h-md)] px-[var(--button-px-md)] py-[var(--button-py-md)] text-base",
|
|
@@ -51,6 +51,6 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
|
|
|
51
51
|
darkMode?: boolean;
|
|
52
52
|
}
|
|
53
53
|
export type ButtonColor = SemanticColor;
|
|
54
|
-
export type ButtonVariant = "filled" | "outline" | "
|
|
54
|
+
export type ButtonVariant = "filled" | "outline" | "soft" | "link";
|
|
55
55
|
export type ButtonSize = "sm" | "md" | "lg";
|
|
56
56
|
export type ButtonState = "default" | "disabled" | "error" | "loading";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { HTMLAttributes } from
|
|
2
|
-
import { CalendarEventThemeOverrides } from
|
|
3
|
-
import { CalendarEvent as CalendarEventType, GridConfig, EventPosition } from
|
|
4
|
-
export type CalendarEventVariant =
|
|
1
|
+
import { HTMLAttributes } from "react";
|
|
2
|
+
import { CalendarEventThemeOverrides } from "./CalendarEvent.theme";
|
|
3
|
+
import { CalendarEvent as CalendarEventType, GridConfig, EventPosition } from "../../../../utils";
|
|
4
|
+
export type CalendarEventVariant = "daily" | "weekly" | "monthly";
|
|
5
5
|
export interface CalendarEventProps extends HTMLAttributes<HTMLDivElement> {
|
|
6
6
|
variant?: CalendarEventVariant;
|
|
7
7
|
event: CalendarEventType & {
|
|
@@ -9,7 +9,6 @@ export interface CalendarEventProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
9
9
|
attendees?: Array<{
|
|
10
10
|
name: string;
|
|
11
11
|
src: string;
|
|
12
|
-
alt: string;
|
|
13
12
|
showTooltip?: boolean;
|
|
14
13
|
}>;
|
|
15
14
|
};
|
|
@@ -20,5 +19,5 @@ export interface CalendarEventProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
20
19
|
gridInterval?: number;
|
|
21
20
|
startOffset?: number;
|
|
22
21
|
theme?: CalendarEventThemeOverrides;
|
|
23
|
-
onEventClick?: (eventData: CalendarEventProps[
|
|
22
|
+
onEventClick?: (eventData: CalendarEventProps["event"]) => void;
|
|
24
23
|
}
|
|
@@ -195,7 +195,7 @@ const CalendarMini = React__default.forwardRef(({ selectedDate, currentMonth, on
|
|
|
195
195
|
};
|
|
196
196
|
const MonthRow = enableAnimations ? motion.div : "div";
|
|
197
197
|
const DateItem = enableAnimations ? motion.button : "button";
|
|
198
|
-
return (jsxs("div", { ref: ref, className: cn(mergedTheme.baseStyle, className), role: "region", "aria-label": "Mini calendar", ...rest, children: [jsx(Button, { iconOnly: true, color: "neutral", variant: "
|
|
198
|
+
return (jsxs("div", { ref: ref, className: cn(mergedTheme.baseStyle, className), role: "region", "aria-label": "Mini calendar", ...rest, children: [jsx(Button, { iconOnly: true, color: "neutral", variant: "soft", className: "!flex-shrink !flex-grow-0 !w-fit self-stretch !h-auto !min-h-0 px-0.5", onClick: handlePrevMonth, "aria-label": "Previous month", children: jsx(ChevronLeftIcon, { className: "size-5 text-[var(--color-text-primary)]" }) }), jsxs("div", { className: "flex flex-col gap-1 relative", children: [jsxs("div", { className: "flex items-center gap-1", children: [jsx("div", { className: "flex flex-col relative overflow-hidden flex-1", style: {
|
|
199
199
|
maskImage: "linear-gradient(to right, transparent, black 16px, black calc(100% - 16px), transparent)",
|
|
200
200
|
WebkitMaskImage: "linear-gradient(to right, transparent, black 16px, black calc(100% - 16px), transparent)",
|
|
201
201
|
}, children: jsx("div", { ref: monthScrollRef, className: cn(mergedTheme.monthRowStyle), role: "tablist", "aria-label": "Month selection", children: jsx(AnimatePresence, { mode: "popLayout", initial: false, custom: direction, children: jsx(MonthRow, { custom: direction, ...(enableAnimations && {
|
|
@@ -243,7 +243,7 @@ const CalendarMini = React__default.forwardRef(({ selectedDate, currentMonth, on
|
|
|
243
243
|
}), "aria-selected": isSelected, "aria-current": isToday ? "date" : undefined, "aria-disabled": disabled, type: "button", ...(enableAnimations && {
|
|
244
244
|
whileTap: !disabled ? { scale: 0.95 } : undefined,
|
|
245
245
|
}), children: [jsx("div", { className: "text-base font-medium opacity-60", children: formatDayName(date) }), jsx("time", { dateTime: date.toISOString(), className: cn("font-semibold"), children: formatDateNumber(date) })] }, date.toISOString()));
|
|
246
|
-
}) }, `${startDate.getTime()}-dates`) }) }) })] }), jsx(Button, { iconOnly: true, color: "neutral", variant: "
|
|
246
|
+
}) }, `${startDate.getTime()}-dates`) }) }) })] }), jsx(Button, { iconOnly: true, color: "neutral", variant: "soft", className: "!flex-shrink !flex-grow-0 !w-fit self-stretch !h-auto !min-h-0 px-0.5", onClick: handleNextMonth, "aria-label": "Next month", children: jsx(ChevronRightIcon, { className: "size-5 text-[var(--color-text-primary)]" }) })] }));
|
|
247
247
|
});
|
|
248
248
|
CalendarMini.displayName = "CalendarMini";
|
|
249
249
|
|
|
@@ -8,7 +8,7 @@ import { XMarkIcon } from '@heroicons/react/24/outline';
|
|
|
8
8
|
const DrawerHeader = ({ children, icon, showCloseButton, className, ...props }) => {
|
|
9
9
|
const { onClose, showCloseButton: contextShowCloseButton, theme, } = useDrawerContext();
|
|
10
10
|
const shouldShowCloseButton = showCloseButton !== null && showCloseButton !== void 0 ? showCloseButton : contextShowCloseButton;
|
|
11
|
-
return (jsxs("div", { className: cn(theme.header, className), ...props, children: [jsxs("div", { className: cn(theme.headerContent), children: [icon && (jsx("div", { className: "flex-shrink-0 text-[var(--color-text-secondary)]", children: icon })), jsx("div", { className: "flex-1 min-w-0", children: children })] }), shouldShowCloseButton && (jsx(Button, { color: "neutral", variant: "
|
|
11
|
+
return (jsxs("div", { className: cn(theme.header, className), ...props, children: [jsxs("div", { className: cn(theme.headerContent), children: [icon && (jsx("div", { className: "flex-shrink-0 text-[var(--color-text-secondary)]", children: icon })), jsx("div", { className: "flex-1 min-w-0", children: children })] }), shouldShowCloseButton && (jsx(Button, { color: "neutral", variant: "soft", iconOnly: true, size: "sm", onClick: onClose, "aria-label": "Close drawer", className: "rounded-full shrink-0", children: jsx(XMarkIcon, { className: "size-5" }) }))] }));
|
|
12
12
|
};
|
|
13
13
|
DrawerHeader.displayName = "Drawer.Header";
|
|
14
14
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import React__default from 'react';
|
|
3
|
+
import { cn } from '../../../utils/cn.js';
|
|
4
|
+
import { fileTypeIconTheme } from './FileTypeIcon.theme.js';
|
|
5
|
+
import { fileTypes } from './fileTypes.js';
|
|
6
|
+
|
|
7
|
+
const FileTypeIcon = React__default.forwardRef(({ type, size = 'md', colorMode = 'color', className, theme: customTheme, ...props }, ref) => {
|
|
8
|
+
var _a;
|
|
9
|
+
const fileType = fileTypes[type];
|
|
10
|
+
if (!fileType) {
|
|
11
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
12
|
+
console.warn(`[FileTypeIcon]: Unknown type "${type}". Available types: ${Object.keys(fileTypes).join(', ')}`);
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const theme = {
|
|
17
|
+
...fileTypeIconTheme,
|
|
18
|
+
...customTheme,
|
|
19
|
+
sizes: { ...fileTypeIconTheme.sizes, ...customTheme === null || customTheme === void 0 ? void 0 : customTheme.sizes },
|
|
20
|
+
};
|
|
21
|
+
const resolvedSize = typeof size === 'number' ? size : (_a = theme.sizes[size]) !== null && _a !== void 0 ? _a : 24;
|
|
22
|
+
const strokeColor = colorMode === 'color' ? '#D5D7DA' : 'currentColor';
|
|
23
|
+
const strokeOpacity = colorMode === 'color' ? 1 : 0.3;
|
|
24
|
+
const badgeColor = colorMode === 'color' ? fileType.color : 'currentColor';
|
|
25
|
+
const labelText = fileType.label;
|
|
26
|
+
const badgeWidth = Math.round(labelText.length * 6 + 8);
|
|
27
|
+
const badgeX = 1;
|
|
28
|
+
const textX = badgeX + badgeWidth / 2;
|
|
29
|
+
return (jsxs("svg", { ref: ref, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 40 40", width: resolvedSize, height: resolvedSize, fill: "none", role: "img", "aria-label": `${fileType.label} file`, "data-type": type, "data-color-mode": colorMode, "data-size": size, className: cn(theme.baseStyle, className), ...props, children: [jsx("path", { d: "M11 0.75H27C27.1212 0.75 27.2375 0.798088 27.3232 0.883789L38.1162 11.6768C38.2019 11.7625 38.25 11.8788 38.25 12V36C38.25 37.7949 36.7949 39.25 35 39.25H11C9.20507 39.25 7.75 37.7949 7.75 36V4C7.75 2.20507 9.20508 0.75 11 0.75Z", stroke: strokeColor, strokeWidth: "1.5", opacity: strokeOpacity }), jsx("path", { d: "M27 0.5V8C27 10.2091 28.7909 12 31 12H38.5", stroke: strokeColor, strokeWidth: "1.5", opacity: strokeOpacity }), jsx("rect", { x: badgeX, y: 18, width: badgeWidth, height: 16, rx: 2, fill: badgeColor, opacity: colorMode === 'color' ? 1 : 0.15 }), jsx("text", { x: textX, y: 26, textAnchor: "middle", dominantBaseline: "central", fill: colorMode === 'color' ? 'white' : 'currentColor', fontSize: 9.5, fontWeight: 700, fontFamily: "Arial, Helvetica, sans-serif", letterSpacing: 0.3, children: labelText })] }));
|
|
30
|
+
});
|
|
31
|
+
FileTypeIcon.displayName = 'FileTypeIcon';
|
|
32
|
+
|
|
33
|
+
export { FileTypeIcon };
|