@flikk/ui 1.0.0-beta.25 → 1.0.0-beta.26

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 (122) hide show
  1. package/dist/components/ai/CodeBlock/CodeBlock.theme.js +2 -2
  2. package/dist/components/ai/PromptInput/PromptInput.js +1 -0
  3. package/dist/components/ai/PromptInput/VoiceRecorder.js +1 -0
  4. package/dist/components/ai/StreamingResponse/MarkdownRenderer.js +1 -1
  5. package/dist/components/ai/TokenCounter/TokenCounter.theme.js +1 -1
  6. package/dist/components/charts/BarChart/BarChart.js +2 -2
  7. package/dist/components/charts/StackedBarChart/StackedBarChart.js +1 -1
  8. package/dist/components/charts/shared/BarRenderer/BarRenderer.js +2 -2
  9. package/dist/components/core/Breadcrumbs/Breadcrumbs.theme.js +1 -1
  10. package/dist/components/core/Button/Button.js +1 -1
  11. package/dist/components/core/Button/Button.theme.js +4 -4
  12. package/dist/components/core/Calendar/CalendarMini/CalendarMini.theme.js +1 -1
  13. package/dist/components/core/ContextMenu/ContextMenu.theme.js +1 -1
  14. package/dist/components/core/Drawer/Drawer.theme.js +2 -2
  15. package/dist/components/core/Dropdown/Dropdown.theme.js +2 -2
  16. package/dist/components/core/Empty/Empty.js +1 -1
  17. package/dist/components/core/ImagePlaceholder/ImagePlaceholder.d.ts +14 -0
  18. package/dist/components/core/ImagePlaceholder/ImagePlaceholder.js +28 -0
  19. package/dist/components/core/ImagePlaceholder/ImagePlaceholder.theme.d.ts +6 -0
  20. package/dist/components/core/ImagePlaceholder/ImagePlaceholder.theme.js +8 -0
  21. package/dist/components/core/ImagePlaceholder/ImagePlaceholder.types.d.ts +32 -0
  22. package/dist/components/core/ImagePlaceholder/index.d.ts +2 -0
  23. package/dist/components/core/Message/Message.theme.js +1 -1
  24. package/dist/components/core/Modal/Modal.theme.js +1 -1
  25. package/dist/components/core/NavItem/NavItem.d.ts +1 -1
  26. package/dist/components/core/NavItem/NavItem.js +171 -68
  27. package/dist/components/core/NavItem/NavItem.theme.js +20 -12
  28. package/dist/components/core/NavItem/NavItem.types.d.ts +17 -39
  29. package/dist/components/core/Pagination/Pagination.theme.js +3 -3
  30. package/dist/components/core/Popover/Popover.theme.js +1 -1
  31. package/dist/components/core/Progress/Progress.theme.js +1 -1
  32. package/dist/components/core/ScrollArea/ScrollArea.js +2 -2
  33. package/dist/components/core/ScrollArea/ScrollArea.theme.js +1 -1
  34. package/dist/components/core/Segmented/Segmented.js +8 -6
  35. package/dist/components/core/Segmented/Segmented.theme.js +3 -3
  36. package/dist/components/core/Sidebar/Sidebar.d.ts +1 -1
  37. package/dist/components/core/Sidebar/Sidebar.js +42 -13
  38. package/dist/components/core/Sidebar/Sidebar.theme.js +5 -7
  39. package/dist/components/core/Sidebar/Sidebar.types.d.ts +33 -4
  40. package/dist/components/core/Sidebar/SidebarContent.js +6 -6
  41. package/dist/components/core/Sidebar/SidebarContext.d.ts +17 -16
  42. package/dist/components/core/Sidebar/SidebarContext.js +42 -19
  43. package/dist/components/core/Sidebar/SidebarFooter.js +4 -6
  44. package/dist/components/core/Sidebar/SidebarHeader.js +4 -9
  45. package/dist/components/core/Sidebar/SidebarLogo.js +3 -7
  46. package/dist/components/core/Sidebar/SidebarNav.js +4 -3
  47. package/dist/components/core/Sidebar/SidebarNavGroup.js +4 -7
  48. package/dist/components/core/Sidebar/SidebarToggle.js +6 -1
  49. package/dist/components/core/Sidebar/SidebarUserProfile.js +33 -17
  50. package/dist/components/core/Sidebar/index.d.ts +2 -3
  51. package/dist/components/core/Skeleton/Skeleton.theme.js +1 -1
  52. package/dist/components/core/Spinner/Spinner.theme.js +1 -1
  53. package/dist/components/core/Tabs/Tabs.js +6 -1
  54. package/dist/components/core/Tabs/Tabs.types.d.ts +2 -0
  55. package/dist/components/core/Tabs/TabsBody.js +5 -3
  56. package/dist/components/core/Tag/Tag.theme.js +1 -1
  57. package/dist/components/core/index.d.ts +1 -0
  58. package/dist/components/core/index.js +2 -2
  59. package/dist/components/data-display/GanttChart/GanttTableGroupRow.js +1 -1
  60. package/dist/components/data-display/KPI/KPI.js +13 -3
  61. package/dist/components/data-display/KPI/KPI.theme.js +3 -3
  62. package/dist/components/data-display/Metric/Metric.theme.js +3 -3
  63. package/dist/components/data-display/Table/Table.js +4 -3
  64. package/dist/components/data-display/Table/Table.theme.js +11 -1
  65. package/dist/components/data-display/Table/Table.types.d.ts +15 -0
  66. package/dist/components/data-display/Table/TableColumnManager.js +1 -1
  67. package/dist/components/data-display/Table/index.d.ts +2 -2
  68. package/dist/components/effects/Aurora/Aurora.js +79 -40
  69. package/dist/components/effects/InteractiveCharacters/InteractiveCharacters.js +3 -3
  70. package/dist/components/effects/InteractiveCharacters/characters/BlobCharacter.js +13 -4
  71. package/dist/components/effects/InteractiveCharacters/characters/SmallCharacter.js +13 -4
  72. package/dist/components/effects/InteractiveCharacters/characters/TallCharacter.js +14 -4
  73. package/dist/components/effects/MorphingText/MorphingText.js +40 -7
  74. package/dist/components/effects/StripePattern/StripePattern.d.ts +18 -0
  75. package/dist/components/effects/StripePattern/StripePattern.js +54 -0
  76. package/dist/components/effects/StripePattern/StripePattern.types.d.ts +53 -0
  77. package/dist/components/effects/StripePattern/index.d.ts +2 -0
  78. package/dist/components/effects/index.d.ts +2 -0
  79. package/dist/components/effects/index.js +1 -0
  80. package/dist/components/forms/Checkbox/Checkbox.theme.js +1 -1
  81. package/dist/components/forms/CronInput/CronInput.theme.js +16 -16
  82. package/dist/components/forms/DatePicker/DatePickerTrigger.js +1 -1
  83. package/dist/components/forms/DateRangePicker/DateRangePicker.theme.js +1 -1
  84. package/dist/components/forms/DateRangePicker/DateRangePickerTrigger.js +1 -1
  85. package/dist/components/forms/FileUpload/FileUpload.js +1 -1
  86. package/dist/components/forms/FileUpload/FileUploadProgress.js +27 -20
  87. package/dist/components/forms/FileUpload/FileUploadProgress.theme.js +2 -2
  88. package/dist/components/forms/Input/Input.theme.js +9 -11
  89. package/dist/components/forms/Mention/Mention.theme.js +3 -3
  90. package/dist/components/forms/Radio/Radio.theme.js +1 -1
  91. package/dist/components/forms/RichTextEditor/RichTextEditor.d.ts +18 -0
  92. package/dist/components/forms/RichTextEditor/RichTextEditor.js +1231 -236
  93. package/dist/components/forms/RichTextEditor/RichTextEditor.theme.d.ts +53 -1
  94. package/dist/components/forms/RichTextEditor/RichTextEditor.theme.js +99 -25
  95. package/dist/components/forms/RichTextEditor/RichTextEditor.types.d.ts +42 -3
  96. package/dist/components/forms/RichTextEditor/index.d.ts +2 -2
  97. package/dist/components/forms/Select/Select.js +1 -1
  98. package/dist/components/forms/Slider/Slider.theme.js +1 -1
  99. package/dist/components/forms/Switch/Switch.theme.js +1 -1
  100. package/dist/components/forms/TimePicker/TimePicker.theme.js +2 -2
  101. package/dist/components/forms/TimePicker/TimePickerContent.js +1 -0
  102. package/dist/components/forms/TimePicker/TimePickerTrigger.js +1 -1
  103. package/dist/components/forms/forms.theme.js +12 -12
  104. package/dist/components/forms/index.js +1 -0
  105. package/dist/components/layout/FormLayout/FormLayout.js +6 -4
  106. package/dist/components/layout/FormLayout/FormLayout.types.d.ts +3 -3
  107. package/dist/components/layout/FormLayout/FormLayoutSection.js +6 -1
  108. package/dist/components/layout/PageLayout/PageLayout.d.ts +2 -2
  109. package/dist/components/layout/PageLayout/PageLayout.js +23 -5
  110. package/dist/components/layout/PageLayout/PageLayout.theme.d.ts +2 -1
  111. package/dist/components/layout/PageLayout/PageLayout.theme.js +35 -6
  112. package/dist/components/layout/PageLayout/PageLayout.types.d.ts +45 -0
  113. package/dist/components/layout/PageLayout/PageLayoutContent.js +6 -4
  114. package/dist/components/layout/PageLayout/PageLayoutHeader.js +3 -3
  115. package/dist/components/layout/PageLayout/PageLayoutSidebar.js +5 -3
  116. package/dist/components/layout/PageLayout/index.d.ts +1 -1
  117. package/dist/index.js +2 -2
  118. package/dist/styles.css +1 -1
  119. package/package.json +1 -1
  120. package/src/styles/theme.css +127 -92
  121. package/dist/components/core/Sidebar/SidebarSubmenu.d.ts +0 -7
  122. package/dist/components/core/Sidebar/SidebarSubmenu.js +0 -12
@@ -1,11 +1,16 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useId } from 'react';
2
3
  import { useTransform, motion } from 'motion/react';
3
4
  import { eyelidVariants, clickTransition, bodyTransition, smallBodyVariants, smallMouthPaths } from '../InteractiveCharacters.animations.js';
4
5
 
5
- const LEFT_EYE = { cx: -14, cy: -32 };
6
- const RIGHT_EYE = { cx: 14, cy: -32 };
6
+ const LEFT_EYE = { cx: -13, cy: -34 };
7
+ const RIGHT_EYE = { cx: 12, cy: -34 };
7
8
  const CLICK_STATES = new Set(['surprised', 'love', 'excited']);
8
9
  const SmallCharacter = ({ state, eyeOffset, idle, blinkAmount, onClick, }) => {
10
+ const id = useId().replace(/:/g, '');
11
+ const leftClipId = `${id}-glyph-eye-l`;
12
+ const rightClipId = `${id}-glyph-eye-r`;
13
+ const bodyGradientId = `${id}-glyph-body`;
9
14
  const leftPupilX = useTransform(eyeOffset.x, (v) => LEFT_EYE.cx + v);
10
15
  const leftPupilY = useTransform(eyeOffset.y, (v) => LEFT_EYE.cy + v);
11
16
  const rightPupilX = useTransform(eyeOffset.x, (v) => RIGHT_EYE.cx + v);
@@ -24,13 +29,17 @@ const SmallCharacter = ({ state, eyeOffset, idle, blinkAmount, onClick, }) => {
24
29
  x: idle.sway,
25
30
  y: idle.bob,
26
31
  scale: idle.breath,
27
- }, onClick: onClick, children: [jsx("path", { d: "M -45 0 Q -45 -60 0 -60 Q 45 -60 45 0 Z", fill: "#FACC15" }), jsxs(motion.g, { style: {
32
+ }, onClick: onClick, children: [jsx("defs", { children: jsxs("linearGradient", { id: bodyGradientId, x1: "-48", y1: "-73", x2: "38", y2: "0", gradientUnits: "userSpaceOnUse", children: [jsx("stop", { stopColor: "#FDA4AF" }), jsx("stop", { offset: "1", stopColor: "#FB7185" })] }) }), jsx(motion.path, { d: "M -38 -28 C -43 -57 -18 -78 13 -67 C 39 -58 50 -27 31 -8 C 13 10 -29 3 -38 -28 Z", fill: `url(#${bodyGradientId})`, animate: {
33
+ d: state === 'excited'
34
+ ? 'M -40 -31 C -47 -63 -17 -85 17 -72 C 45 -61 56 -27 33 -5 C 12 15 -31 5 -40 -31 Z'
35
+ : 'M -38 -28 C -43 -57 -18 -78 13 -67 C 39 -58 50 -27 31 -8 C 13 10 -29 3 -38 -28 Z',
36
+ }, transition: transition }), jsx("path", { d: "M 20 -59 C 38 -47 42 -26 31 -13", fill: "none", stroke: "#FFE4E6", strokeWidth: 4, strokeLinecap: "round", opacity: 0.5 }), jsx("circle", { cx: -44, cy: -61, r: 7, fill: "#38BDF8", opacity: state === 'excited' ? 0.95 : 0.65 }), jsxs(motion.g, { style: {
28
37
  originX: '0px',
29
38
  originY: '-30px',
30
39
  rotate: combinedHeadRotate,
31
40
  x: combinedHeadX,
32
41
  y: combinedHeadY,
33
- }, children: [jsxs("g", { children: [jsx("clipPath", { id: "small-eye-l", children: jsx("circle", { cx: LEFT_EYE.cx, cy: LEFT_EYE.cy, r: 10 }) }), jsx("circle", { cx: LEFT_EYE.cx, cy: LEFT_EYE.cy, r: 10, fill: "white" }), jsx(motion.circle, { cx: leftPupilX, cy: leftPupilY, r: 6, fill: "#1E293B", clipPath: "url(#small-eye-l)" }), jsx("circle", { cx: LEFT_EYE.cx + 3, cy: LEFT_EYE.cy - 4, r: 2.2, fill: "white", opacity: 0.95 }), jsx("circle", { cx: LEFT_EYE.cx - 2, cy: LEFT_EYE.cy + 3, r: 1.1, fill: "white", opacity: 0.7 }), jsx(motion.rect, { x: LEFT_EYE.cx - 10, y: LEFT_EYE.cy - 10, width: 20, height: 20, fill: "#FACC15", rx: 2, style: { scaleY: eyelidScale, originX: '50%', originY: '0%', transformBox: 'fill-box' } })] }), jsxs("g", { children: [jsx("clipPath", { id: "small-eye-r", children: jsx("circle", { cx: RIGHT_EYE.cx, cy: RIGHT_EYE.cy, r: 10 }) }), jsx("circle", { cx: RIGHT_EYE.cx, cy: RIGHT_EYE.cy, r: 10, fill: "white" }), jsx(motion.circle, { cx: rightPupilX, cy: rightPupilY, r: 6, fill: "#1E293B", clipPath: "url(#small-eye-r)" }), jsx("circle", { cx: RIGHT_EYE.cx + 3, cy: RIGHT_EYE.cy - 4, r: 2.2, fill: "white", opacity: 0.95 }), jsx("circle", { cx: RIGHT_EYE.cx - 2, cy: RIGHT_EYE.cy + 3, r: 1.1, fill: "white", opacity: 0.7 }), jsx(motion.rect, { x: RIGHT_EYE.cx - 10, y: RIGHT_EYE.cy - 10, width: 20, height: 20, fill: "#FACC15", rx: 2, style: { scaleY: eyelidScale, originX: '50%', originY: '0%', transformBox: 'fill-box' } })] }), jsx("ellipse", { cx: -22, cy: -18, rx: 6, ry: 4, fill: "#FDE68A", opacity: state === 'excited' ? 0.85 : 0.6 }), jsx("ellipse", { cx: 22, cy: -18, rx: 6, ry: 4, fill: "#FDE68A", opacity: state === 'excited' ? 0.85 : 0.6 }), jsx(motion.path, { d: smallMouthPaths[state], fill: "none", stroke: "#1E293B", strokeWidth: 2, strokeLinecap: "round", animate: { d: smallMouthPaths[state] }, transition: transition, transform: "translate(0, -14)" })] })] }));
42
+ }, children: [jsxs("g", { children: [jsx("clipPath", { id: leftClipId, children: jsx("circle", { cx: LEFT_EYE.cx, cy: LEFT_EYE.cy, r: 10 }) }), jsx("circle", { cx: LEFT_EYE.cx, cy: LEFT_EYE.cy, r: 8.5, fill: "#FFF7ED" }), jsx(motion.circle, { cx: leftPupilX, cy: leftPupilY, r: 5.5, fill: "#253040", clipPath: `url(#${leftClipId})` }), jsx("circle", { cx: LEFT_EYE.cx + 3, cy: LEFT_EYE.cy - 4, r: 2.2, fill: "white", opacity: 0.95 }), jsx("circle", { cx: LEFT_EYE.cx - 2, cy: LEFT_EYE.cy + 3, r: 1.1, fill: "white", opacity: 0.7 }), jsx(motion.rect, { x: LEFT_EYE.cx - 8.5, y: LEFT_EYE.cy - 8.5, width: 17, height: 17, fill: "#FB7B8C", rx: 2, style: { scaleY: eyelidScale, originX: '50%', originY: '0%', transformBox: 'fill-box' } })] }), jsxs("g", { children: [jsx("clipPath", { id: rightClipId, children: jsx("circle", { cx: RIGHT_EYE.cx, cy: RIGHT_EYE.cy, r: 10 }) }), jsx("circle", { cx: RIGHT_EYE.cx, cy: RIGHT_EYE.cy, r: 8.5, fill: "#FFF7ED" }), jsx(motion.circle, { cx: rightPupilX, cy: rightPupilY, r: 5.5, fill: "#253040", clipPath: `url(#${rightClipId})` }), jsx("circle", { cx: RIGHT_EYE.cx + 3, cy: RIGHT_EYE.cy - 4, r: 2.2, fill: "white", opacity: 0.95 }), jsx("circle", { cx: RIGHT_EYE.cx - 2, cy: RIGHT_EYE.cy + 3, r: 1.1, fill: "white", opacity: 0.7 }), jsx(motion.rect, { x: RIGHT_EYE.cx - 8.5, y: RIGHT_EYE.cy - 8.5, width: 17, height: 17, fill: "#FB7B8C", rx: 2, style: { scaleY: eyelidScale, originX: '50%', originY: '0%', transformBox: 'fill-box' } })] }), jsx("ellipse", { cx: -25, cy: -20, rx: 5, ry: 3, fill: "#FFE4E6", opacity: state === 'excited' ? 0.9 : 0.55 }), jsx("ellipse", { cx: 23, cy: -20, rx: 5, ry: 3, fill: "#FFE4E6", opacity: state === 'excited' ? 0.9 : 0.55 }), jsx(motion.path, { d: smallMouthPaths[state], fill: "none", stroke: "#1E293B", strokeWidth: 2, strokeLinecap: "round", animate: { d: smallMouthPaths[state] }, transition: transition, transform: "translate(0, -17)" })] })] }));
34
43
  };
35
44
 
36
45
  export { SmallCharacter };
@@ -1,11 +1,17 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useId } from 'react';
2
3
  import { useTransform, motion } from 'motion/react';
3
4
  import { eyelidVariants, clickTransition, bodyTransition, tallBodyVariants, eyebrowVariants, tallMouthPaths } from '../InteractiveCharacters.animations.js';
4
5
 
5
- const LEFT_EYE = { cx: -12, cy: -82 };
6
- const RIGHT_EYE = { cx: 12, cy: -82 };
6
+ const LEFT_EYE = { cx: -12, cy: -73 };
7
+ const RIGHT_EYE = { cx: 12, cy: -73 };
7
8
  const CLICK_STATES = new Set(['surprised', 'love', 'excited']);
8
9
  const TallCharacter = ({ state, eyeOffset, idle, blinkAmount, onClick, }) => {
10
+ const id = useId().replace(/:/g, '');
11
+ const leftClipId = `${id}-stack-eye-l`;
12
+ const rightClipId = `${id}-stack-eye-r`;
13
+ const topGradientId = `${id}-stack-top`;
14
+ const baseGradientId = `${id}-stack-base`;
9
15
  const leftPupilX = useTransform(eyeOffset.x, (v) => LEFT_EYE.cx + v);
10
16
  const leftPupilY = useTransform(eyeOffset.y, (v) => LEFT_EYE.cy + v);
11
17
  const rightPupilX = useTransform(eyeOffset.x, (v) => RIGHT_EYE.cx + v);
@@ -25,13 +31,17 @@ const TallCharacter = ({ state, eyeOffset, idle, blinkAmount, onClick, }) => {
25
31
  x: idle.sway,
26
32
  y: idle.bob,
27
33
  scale: idle.breath,
28
- }, onClick: onClick, children: [jsx("rect", { x: -30, y: -140, width: 60, height: 140, rx: 22, fill: "#8B5CF6" }), jsxs(motion.g, { style: {
34
+ }, onClick: onClick, children: [jsxs("defs", { children: [jsxs("linearGradient", { id: topGradientId, x1: "-33", y1: "-128", x2: "34", y2: "-54", gradientUnits: "userSpaceOnUse", children: [jsx("stop", { stopColor: "#A5B4FC" }), jsx("stop", { offset: "1", stopColor: "#6366F1" })] }), jsxs("linearGradient", { id: baseGradientId, x1: "-46", y1: "-69", x2: "45", y2: "0", gradientUnits: "userSpaceOnUse", children: [jsx("stop", { stopColor: "#67E8F9" }), jsx("stop", { offset: "1", stopColor: "#14B8A6" })] })] }), jsx(motion.path, { d: "M -20 -132 C 8 -146 37 -124 34 -94 C 32 -70 8 -57 -16 -65 C -42 -74 -47 -117 -20 -132 Z", fill: `url(#${topGradientId})`, animate: {
35
+ d: state === 'love'
36
+ ? 'M -22 -136 C 9 -153 42 -126 37 -92 C 34 -66 8 -53 -18 -63 C -48 -74 -51 -120 -22 -136 Z'
37
+ : 'M -20 -132 C 8 -146 37 -124 34 -94 C 32 -70 8 -57 -16 -65 C -42 -74 -47 -117 -20 -132 Z',
38
+ }, transition: transition }), jsx("path", { d: "M -39 -63 C -15 -86 31 -78 43 -47 C 55 -13 28 9 -10 4 C -47 -1 -66 -35 -39 -63 Z", fill: `url(#${baseGradientId})` }), jsx("path", { d: "M -25 -121 C -6 -132 15 -129 25 -112", fill: "none", stroke: "#E0E7FF", strokeLinecap: "round", strokeWidth: 4, opacity: 0.48 }), jsxs(motion.g, { style: {
29
39
  originX: '0px',
30
40
  originY: '-70px',
31
41
  rotate: combinedHeadRotate,
32
42
  x: combinedHeadX,
33
43
  y: combinedHeadY,
34
- }, children: [jsx(motion.line, { x1: -22, y1: -103, x2: -4, y2: -103, stroke: "#1E293B", strokeWidth: 2.5, strokeLinecap: "round", animate: { rotate: eyebrow.rotate, y: eyebrow.y }, transition: transition, style: { originX: '50%', originY: '50%', transformBox: 'fill-box' } }), jsx(motion.line, { x1: 4, y1: -103, x2: 22, y2: -103, stroke: "#1E293B", strokeWidth: 2.5, strokeLinecap: "round", animate: { rotate: -eyebrow.rotate, y: eyebrow.y }, transition: transition, style: { originX: '50%', originY: '50%', transformBox: 'fill-box' } }), jsxs("g", { children: [jsx("clipPath", { id: "tall-eye-l", children: jsx("ellipse", { cx: LEFT_EYE.cx, cy: LEFT_EYE.cy, rx: 11, ry: 14 }) }), jsx("ellipse", { cx: LEFT_EYE.cx, cy: LEFT_EYE.cy, rx: 11, ry: 14, fill: "white" }), jsx(motion.circle, { cx: leftPupilX, cy: leftPupilY, r: 6.5, fill: "#1E293B", clipPath: "url(#tall-eye-l)" }), jsx("circle", { cx: LEFT_EYE.cx + 3.5, cy: LEFT_EYE.cy - 5, r: 2.5, fill: "white", opacity: 0.95 }), jsx("circle", { cx: LEFT_EYE.cx - 2.5, cy: LEFT_EYE.cy + 3, r: 1.2, fill: "white", opacity: 0.7 }), jsx(motion.rect, { x: LEFT_EYE.cx - 11, y: LEFT_EYE.cy - 14, width: 22, height: 28, fill: "#8B5CF6", rx: 2, style: { scaleY: eyelidScale, originX: '50%', originY: '0%', transformBox: 'fill-box' } })] }), jsxs("g", { children: [jsx("clipPath", { id: "tall-eye-r", children: jsx("ellipse", { cx: RIGHT_EYE.cx, cy: RIGHT_EYE.cy, rx: 11, ry: 14 }) }), jsx("ellipse", { cx: RIGHT_EYE.cx, cy: RIGHT_EYE.cy, rx: 11, ry: 14, fill: "white" }), jsx(motion.circle, { cx: rightPupilX, cy: rightPupilY, r: 6.5, fill: "#1E293B", clipPath: "url(#tall-eye-r)" }), jsx("circle", { cx: RIGHT_EYE.cx + 3.5, cy: RIGHT_EYE.cy - 5, r: 2.5, fill: "white", opacity: 0.95 }), jsx("circle", { cx: RIGHT_EYE.cx - 2.5, cy: RIGHT_EYE.cy + 3, r: 1.2, fill: "white", opacity: 0.7 }), jsx(motion.rect, { x: RIGHT_EYE.cx - 11, y: RIGHT_EYE.cy - 14, width: 22, height: 28, fill: "#8B5CF6", rx: 2, style: { scaleY: eyelidScale, originX: '50%', originY: '0%', transformBox: 'fill-box' } })] }), jsx("ellipse", { cx: -22, cy: -62, rx: 7, ry: 5, fill: "#F9A8D4", opacity: state === 'love' ? 0.65 : 0.45 }), jsx("ellipse", { cx: 22, cy: -62, rx: 7, ry: 5, fill: "#F9A8D4", opacity: state === 'love' ? 0.65 : 0.45 }), jsx(motion.path, { d: tallMouthPaths[state], fill: "none", stroke: "#1E293B", strokeWidth: 2, strokeLinecap: "round", animate: { d: tallMouthPaths[state] }, transition: transition, transform: "translate(0, -55)" })] })] }));
44
+ }, children: [jsx(motion.line, { x1: -23, y1: -94, x2: -5, y2: -94, stroke: "#1E293B", strokeWidth: 2.5, strokeLinecap: "round", animate: { rotate: eyebrow.rotate, y: eyebrow.y }, transition: transition, style: { originX: '50%', originY: '50%', transformBox: 'fill-box' } }), jsx(motion.line, { x1: 5, y1: -94, x2: 23, y2: -94, stroke: "#1E293B", strokeWidth: 2.5, strokeLinecap: "round", animate: { rotate: -eyebrow.rotate, y: eyebrow.y }, transition: transition, style: { originX: '50%', originY: '50%', transformBox: 'fill-box' } }), jsxs("g", { children: [jsx("clipPath", { id: leftClipId, children: jsx("ellipse", { cx: LEFT_EYE.cx, cy: LEFT_EYE.cy, rx: 11, ry: 14 }) }), jsx("ellipse", { cx: LEFT_EYE.cx, cy: LEFT_EYE.cy, rx: 10, ry: 12, fill: "#F8FAFC" }), jsx(motion.circle, { cx: leftPupilX, cy: leftPupilY, r: 6.5, fill: "#1E293B", clipPath: `url(#${leftClipId})` }), jsx("circle", { cx: LEFT_EYE.cx + 3.5, cy: LEFT_EYE.cy - 5, r: 2.5, fill: "white", opacity: 0.95 }), jsx("circle", { cx: LEFT_EYE.cx - 2.5, cy: LEFT_EYE.cy + 3, r: 1.2, fill: "white", opacity: 0.7 }), jsx(motion.rect, { x: LEFT_EYE.cx - 10, y: LEFT_EYE.cy - 12, width: 20, height: 24, fill: "#7C83F3", rx: 3, style: { scaleY: eyelidScale, originX: '50%', originY: '0%', transformBox: 'fill-box' } })] }), jsxs("g", { children: [jsx("clipPath", { id: rightClipId, children: jsx("ellipse", { cx: RIGHT_EYE.cx, cy: RIGHT_EYE.cy, rx: 11, ry: 14 }) }), jsx("ellipse", { cx: RIGHT_EYE.cx, cy: RIGHT_EYE.cy, rx: 10, ry: 12, fill: "#F8FAFC" }), jsx(motion.circle, { cx: rightPupilX, cy: rightPupilY, r: 6.5, fill: "#1E293B", clipPath: `url(#${rightClipId})` }), jsx("circle", { cx: RIGHT_EYE.cx + 3.5, cy: RIGHT_EYE.cy - 5, r: 2.5, fill: "white", opacity: 0.95 }), jsx("circle", { cx: RIGHT_EYE.cx - 2.5, cy: RIGHT_EYE.cy + 3, r: 1.2, fill: "white", opacity: 0.7 }), jsx(motion.rect, { x: RIGHT_EYE.cx - 10, y: RIGHT_EYE.cy - 12, width: 20, height: 24, fill: "#7C83F3", rx: 3, style: { scaleY: eyelidScale, originX: '50%', originY: '0%', transformBox: 'fill-box' } })] }), jsx("ellipse", { cx: -25, cy: -57, rx: 6, ry: 3.5, fill: "#C4B5FD", opacity: state === 'love' ? 0.75 : 0.45 }), jsx("ellipse", { cx: 25, cy: -57, rx: 6, ry: 3.5, fill: "#C4B5FD", opacity: state === 'love' ? 0.75 : 0.45 }), jsx(motion.path, { d: tallMouthPaths[state], fill: "none", stroke: "#1E293B", strokeWidth: 2, strokeLinecap: "round", animate: { d: tallMouthPaths[state] }, transition: transition, transform: "translate(0, -49)" })] })] }));
35
45
  };
36
46
 
37
47
  export { TallCharacter };
@@ -1,8 +1,9 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import React__default, { useId, useState, useRef, useCallback, useEffect } from 'react';
3
- import { useReducedMotion, AnimatePresence, motion } from 'motion/react';
2
+ import React__default, { useState, useRef, useCallback, useEffect, useLayoutEffect } from 'react';
3
+ import { useReducedMotion, motion, AnimatePresence } from 'motion/react';
4
4
  import { cn } from '../../../utils/cn.js';
5
5
 
6
+ const useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect;
6
7
  /**
7
8
  * MorphingText smoothly morphs between different text strings using a blur/fade
8
9
  * transition. Two overlapping text layers cross-fade with a Gaussian blur effect
@@ -18,11 +19,12 @@ import { cn } from '../../../utils/cn.js';
18
19
  * ```
19
20
  */
20
21
  const MorphingText = React__default.forwardRef(({ texts, interval = 3000, transitionDuration = 800, loop = true, pauseOnHover = false, currentIndex: controlledIndex, onTextChange, className, ...props }, ref) => {
21
- const filterId = useId();
22
22
  const shouldReduceMotion = useReducedMotion();
23
23
  const isControlled = controlledIndex !== undefined;
24
24
  const [internalIndex, setInternalIndex] = useState(0);
25
25
  const activeIndex = isControlled ? controlledIndex : internalIndex;
26
+ const measureRefs = useRef([]);
27
+ const [textRects, setTextRects] = useState([]);
26
28
  const [isPaused, setIsPaused] = useState(false);
27
29
  const intervalRef = useRef(null);
28
30
  const hasReachedEnd = useRef(false);
@@ -59,6 +61,28 @@ const MorphingText = React__default.forwardRef(({ texts, interval = 3000, transi
59
61
  useEffect(() => {
60
62
  hasReachedEnd.current = false;
61
63
  }, [loop, texts]);
64
+ useIsomorphicLayoutEffect(() => {
65
+ const measure = () => {
66
+ setTextRects(texts.map((_, index) => {
67
+ var _a, _b, _c;
68
+ const rect = (_a = measureRefs.current[index]) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
69
+ return {
70
+ width: (_b = rect === null || rect === void 0 ? void 0 : rect.width) !== null && _b !== void 0 ? _b : 0,
71
+ height: (_c = rect === null || rect === void 0 ? void 0 : rect.height) !== null && _c !== void 0 ? _c : 0,
72
+ };
73
+ }));
74
+ };
75
+ measure();
76
+ if (typeof ResizeObserver === 'undefined') {
77
+ return;
78
+ }
79
+ const observer = new ResizeObserver(measure);
80
+ measureRefs.current.forEach((element) => {
81
+ if (element)
82
+ observer.observe(element);
83
+ });
84
+ return () => observer.disconnect();
85
+ }, [texts]);
62
86
  // Fire onTextChange for controlled index changes
63
87
  useEffect(() => {
64
88
  if (isControlled) {
@@ -78,14 +102,23 @@ const MorphingText = React__default.forwardRef(({ texts, interval = 3000, transi
78
102
  }
79
103
  const durationSeconds = transitionDuration / 1000;
80
104
  const currentText = texts[safeIndex];
105
+ const currentRect = textRects[safeIndex];
106
+ const measuredSize = (currentRect === null || currentRect === void 0 ? void 0 : currentRect.width) && (currentRect === null || currentRect === void 0 ? void 0 : currentRect.height)
107
+ ? { width: currentRect.width, height: currentRect.height }
108
+ : undefined;
81
109
  // Reduced motion: instant swap with no animation
82
110
  if (shouldReduceMotion) {
83
111
  return (jsx("div", { ref: ref, className: cn('relative inline-block', className), onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, "aria-live": "polite", "aria-atomic": "true", ...props, children: jsx("span", { children: currentText }) }));
84
112
  }
85
- return (jsxs("div", { ref: ref, className: cn('relative inline-block', className), onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, "aria-live": "polite", "aria-atomic": "true", ...props, children: [jsx("svg", { className: "absolute h-0 w-0", "aria-hidden": "true", children: jsx("defs", { children: jsx("filter", { id: `${filterId}-blur`, children: jsx("feGaussianBlur", { in: "SourceGraphic", stdDeviation: "0" }) }) }) }), jsx("span", { className: "invisible block", "aria-hidden": "true", children: currentText }), jsx(AnimatePresence, { mode: "popLayout", initial: false, children: jsx(motion.span, { className: "absolute inset-0 flex items-center", initial: { opacity: 0, filter: 'blur(8px)' }, animate: { opacity: 1, filter: 'blur(0px)' }, exit: { opacity: 0, filter: 'blur(8px)' }, transition: {
86
- duration: durationSeconds,
87
- ease: 'easeInOut',
88
- }, children: currentText }, safeIndex) })] }));
113
+ return (jsx("div", { ref: ref, className: cn('relative inline-block align-bottom', className), onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, "aria-live": "polite", "aria-atomic": "true", ...props, children: jsxs(motion.span, { className: "relative inline-block align-bottom", initial: false, animate: measuredSize, transition: {
114
+ duration: durationSeconds,
115
+ ease: 'easeInOut',
116
+ }, children: [jsx("span", { className: "pointer-events-none invisible absolute left-0 top-0 whitespace-nowrap", "aria-hidden": "true", children: texts.map((text, index) => (jsx("span", { ref: (element) => {
117
+ measureRefs.current[index] = element;
118
+ }, className: "block w-fit whitespace-nowrap", children: text }, `${text}-${index}`))) }), !measuredSize && (jsx("span", { className: "whitespace-nowrap", children: currentText })), measuredSize && (jsx(AnimatePresence, { mode: "popLayout", initial: false, children: jsx(motion.span, { className: "absolute left-0 top-0 flex whitespace-nowrap", initial: { opacity: 0, filter: 'blur(8px)' }, animate: { opacity: 1, filter: 'blur(0px)' }, exit: { opacity: 0, filter: 'blur(8px)' }, transition: {
119
+ duration: durationSeconds,
120
+ ease: 'easeInOut',
121
+ }, children: currentText }, safeIndex) }))] }) }));
89
122
  });
90
123
  MorphingText.displayName = "MorphingText";
91
124
 
@@ -0,0 +1,18 @@
1
+ import React from "react";
2
+ import type { StripePatternProps } from "./StripePattern.types";
3
+ /**
4
+ * StripePattern renders an SVG-based diagonal stripe background pattern.
5
+ *
6
+ * Use it as an absolute-positioned decorative or placeholder fill inside a
7
+ * container with `position: relative`. The pattern is non-interactive
8
+ * (`pointer-events: none`) and sits at `z-index: 0` by default.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * <div className="relative overflow-hidden h-40 rounded-lg">
13
+ * <StripePattern />
14
+ * <div className="relative z-10">Empty cover slot</div>
15
+ * </div>
16
+ * ```
17
+ */
18
+ export declare const StripePattern: React.ForwardRefExoticComponent<StripePatternProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,54 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import React__default, { useId, useMemo } from 'react';
3
+ import { useReducedMotion, motion } from 'motion/react';
4
+ import { cn } from '../../../utils/cn.js';
5
+
6
+ function buildMaskImage(direction, fadeSize) {
7
+ const stop = Math.max(0, Math.min(100, fadeSize));
8
+ if (direction === "radial") {
9
+ return `radial-gradient(ellipse at center, black ${100 - stop}%, transparent 100%)`;
10
+ }
11
+ const directionMap = {
12
+ top: "to top",
13
+ bottom: "to bottom",
14
+ left: "to left",
15
+ right: "to right",
16
+ };
17
+ return `linear-gradient(${directionMap[direction]}, black ${100 - stop}%, transparent 100%)`;
18
+ }
19
+ /**
20
+ * StripePattern renders an SVG-based diagonal stripe background pattern.
21
+ *
22
+ * Use it as an absolute-positioned decorative or placeholder fill inside a
23
+ * container with `position: relative`. The pattern is non-interactive
24
+ * (`pointer-events: none`) and sits at `z-index: 0` by default.
25
+ *
26
+ * @example
27
+ * ```tsx
28
+ * <div className="relative overflow-hidden h-40 rounded-lg">
29
+ * <StripePattern />
30
+ * <div className="relative z-10">Empty cover slot</div>
31
+ * </div>
32
+ * ```
33
+ */
34
+ const StripePattern = React__default.forwardRef(({ spacing = 12, strokeWidth = 6, angle = -45, color = "color-mix(in srgb, var(--color-border) 50%, transparent)", fade = false, fadeDirection = "radial", fadeSize = 50, animated = false, className, style, ...rest }, ref) => {
35
+ const patternId = useId();
36
+ const shouldReduceMotion = useReducedMotion();
37
+ const enableAnimation = animated && !shouldReduceMotion;
38
+ const maskImage = useMemo(() => (fade ? buildMaskImage(fadeDirection, fadeSize) : undefined), [fade, fadeDirection, fadeSize]);
39
+ const containerStyle = {
40
+ ...style,
41
+ ...(maskImage
42
+ ? {
43
+ maskImage,
44
+ WebkitMaskImage: maskImage,
45
+ }
46
+ : {}),
47
+ };
48
+ const lineX = spacing / 2;
49
+ const lineElement = enableAnimation ? (jsx(motion.line, { x1: lineX, y1: 0, x2: lineX, y2: spacing, stroke: color, strokeWidth: strokeWidth, animate: { opacity: [0.4, 1, 0.4] }, transition: { duration: 4, ease: "easeInOut", repeat: Infinity } })) : (jsx("line", { x1: lineX, y1: 0, x2: lineX, y2: spacing, stroke: color, strokeWidth: strokeWidth }));
50
+ return (jsx("div", { ref: ref, className: cn("absolute inset-0 pointer-events-none z-0 overflow-hidden", className), style: containerStyle, ...rest, children: jsxs("svg", { "aria-hidden": "true", className: "absolute inset-0 w-full h-full", children: [jsx("defs", { children: jsx("pattern", { id: patternId, x: "0", y: "0", width: spacing, height: spacing, patternUnits: "userSpaceOnUse", patternTransform: `rotate(${angle})`, children: lineElement }) }), jsx("rect", { width: "100%", height: "100%", fill: `url(#${patternId})` })] }) }));
51
+ });
52
+ StripePattern.displayName = "StripePattern";
53
+
54
+ export { StripePattern };
@@ -0,0 +1,53 @@
1
+ import React from "react";
2
+ /** Direction for the fade gradient mask */
3
+ export type StripePatternFadeDirection = "radial" | "top" | "bottom" | "left" | "right";
4
+ export interface StripePatternProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ /**
6
+ * Distance between adjacent stripes in pixels (center to center).
7
+ * @default 12
8
+ */
9
+ spacing?: number;
10
+ /**
11
+ * Thickness of each stripe in pixels.
12
+ * @default 6
13
+ */
14
+ strokeWidth?: number;
15
+ /**
16
+ * Stripe rotation in degrees. `-45` runs bottom-left to top-right.
17
+ * @default -45
18
+ */
19
+ angle?: number;
20
+ /**
21
+ * Stroke color of the stripes.
22
+ * Accepts any valid CSS color value or CSS variable.
23
+ * @default "color-mix(in srgb, var(--color-border) 50%, transparent)"
24
+ */
25
+ color?: string;
26
+ /**
27
+ * Whether to apply a gradient mask that fades the pattern at the edges.
28
+ * Defaults to `false` so the pattern reads as a flat fill — useful for
29
+ * placeholder surfaces. Set to `true` for decorative backgrounds.
30
+ * @default false
31
+ */
32
+ fade?: boolean;
33
+ /**
34
+ * Direction of the fade gradient.
35
+ * - "radial" fades from center outward
36
+ * - "top" | "bottom" | "left" | "right" fades toward that edge
37
+ * @default "radial"
38
+ */
39
+ fadeDirection?: StripePatternFadeDirection;
40
+ /**
41
+ * Size of the fade area as a percentage (0-100).
42
+ * @default 50
43
+ */
44
+ fadeSize?: number;
45
+ /**
46
+ * Whether to apply a subtle pulse animation to the stripes.
47
+ * Respects prefers-reduced-motion automatically.
48
+ * @default false
49
+ */
50
+ animated?: boolean;
51
+ /** Additional className for style overrides (shadcn pattern). */
52
+ className?: string;
53
+ }
@@ -0,0 +1,2 @@
1
+ export { StripePattern } from "./StripePattern";
2
+ export type { StripePatternProps, StripePatternFadeDirection, } from "./StripePattern.types";
@@ -20,6 +20,8 @@ export { GridPattern } from "./GridPattern";
20
20
  export type { GridPatternProps, GridPatternFadeDirection, } from "./GridPattern";
21
21
  export { DotPattern } from "./DotPattern";
22
22
  export type { DotPatternProps, DotPatternFadeDirection, } from "./DotPattern";
23
+ export { StripePattern } from "./StripePattern";
24
+ export type { StripePatternProps, StripePatternFadeDirection, } from "./StripePattern";
23
25
  export { NoiseOverlay } from "./NoiseOverlay";
24
26
  export type { NoiseOverlayProps, NoiseBlendMode } from "./NoiseOverlay";
25
27
  export { Spotlight } from "./Spotlight";
@@ -9,6 +9,7 @@ export { MagneticElement } from './MagneticElement/MagneticElement.js';
9
9
  export { MorphingText } from './MorphingText/MorphingText.js';
10
10
  export { GridPattern } from './GridPattern/GridPattern.js';
11
11
  export { DotPattern } from './DotPattern/DotPattern.js';
12
+ export { StripePattern } from './StripePattern/StripePattern.js';
12
13
  export { NoiseOverlay } from './NoiseOverlay/NoiseOverlay.js';
13
14
  export { Spotlight } from './Spotlight/Spotlight.js';
14
15
  export { SpotlightBorder } from './SpotlightBorder/SpotlightBorder.js';
@@ -10,7 +10,7 @@ const checkboxTheme = {
10
10
  // Default state - light
11
11
  "border-[var(--color-border)] bg-[var(--color-surface)] " +
12
12
  // Default state - dark
13
- "dark:bg-[var(--color-background-tertiary)] " +
13
+ "dark:bg-[var(--color-surface-raised)] " +
14
14
  // Checked state - light
15
15
  "checked:border-[var(--color-primary)] checked:bg-[var(--color-primary)] " +
16
16
  // Checked state - dark
@@ -16,13 +16,13 @@ const cronInputTheme = {
16
16
  // Field label
17
17
  fieldLabelStyle: "text-xs font-medium text-[var(--color-text-secondary)] dark:text-[var(--color-neutral-400)]",
18
18
  // Select dropdown
19
- fieldSelectStyle: "w-full rounded-[var(--form-radius)] outline outline-1 outline-[var(--color-border)] " +
19
+ fieldSelectStyle: "w-full rounded-[var(--form-radius)] outline-none shadow-[inset_0_0_0_1px_var(--color-border)] " +
20
20
  "bg-white text-[var(--color-text-primary)] cursor-pointer transition-all " +
21
- "focus:outline-2 focus:outline-[var(--color-primary-600)] focus:-outline-offset-1 " +
21
+ "focus:shadow-[inset_0_0_0_2px_var(--color-primary-600)] " +
22
22
  "focus:ring-4 focus:ring-[var(--color-primary)]/10 " +
23
23
  "disabled:cursor-not-allowed disabled:bg-[var(--color-background-disabled)] disabled:text-[var(--color-text-disabled)] " +
24
- "dark:bg-[var(--color-neutral-900)] dark:outline-[var(--color-neutral-700)] dark:text-[var(--color-neutral-200)] " +
25
- "dark:focus:outline-[var(--color-primary-500)] dark:focus:ring-[var(--color-primary-500)]/20",
24
+ "dark:bg-[var(--color-neutral-900)] dark:shadow-[inset_0_0_0_1px_var(--color-neutral-700)] dark:text-[var(--color-neutral-200)] " +
25
+ "dark:focus:shadow-[inset_0_0_0_2px_var(--color-primary-500)] dark:focus:ring-[var(--color-primary-500)]/20",
26
26
  // Size variants for field selects
27
27
  fieldSelectSizes: {
28
28
  sm: `${formsBaseTheme.sizes.sm.text} ${formsBaseTheme.sizes.sm.padding} ${formsBaseTheme.sizes.sm.height}`,
@@ -30,14 +30,14 @@ const cronInputTheme = {
30
30
  lg: `${formsBaseTheme.sizes.lg.text} ${formsBaseTheme.sizes.lg.padding} ${formsBaseTheme.sizes.lg.height}`,
31
31
  },
32
32
  // Raw input field
33
- rawInputStyle: "w-full rounded-[var(--form-radius)] outline outline-1 outline-[var(--color-border)] " +
33
+ rawInputStyle: "w-full rounded-[var(--form-radius)] outline-none shadow-[inset_0_0_0_1px_var(--color-border)] " +
34
34
  "bg-white text-[var(--color-text-primary)] font-mono transition-all " +
35
35
  "placeholder:text-[var(--color-text-placeholder)] focus:outline-none " +
36
- "focus:outline-2 focus:outline-[var(--color-primary-600)] focus:-outline-offset-1 " +
36
+ "focus:shadow-[inset_0_0_0_2px_var(--color-primary-600)] " +
37
37
  "focus:ring-4 focus:ring-[var(--color-primary)]/10 " +
38
38
  "disabled:cursor-not-allowed disabled:bg-[var(--color-background-disabled)] disabled:text-[var(--color-text-disabled)] " +
39
- "dark:bg-[var(--color-neutral-900)] dark:outline-[var(--color-neutral-700)] dark:text-[var(--color-neutral-200)] " +
40
- "dark:focus:outline-[var(--color-primary-500)] dark:focus:ring-[var(--color-primary-500)]/20",
39
+ "dark:bg-[var(--color-neutral-900)] dark:shadow-[inset_0_0_0_1px_var(--color-neutral-700)] dark:text-[var(--color-neutral-200)] " +
40
+ "dark:focus:shadow-[inset_0_0_0_2px_var(--color-primary-500)] dark:focus:ring-[var(--color-primary-500)]/20",
41
41
  // Size variants for raw input
42
42
  rawInputSizes: {
43
43
  sm: `${formsBaseTheme.sizes.sm.text} ${formsBaseTheme.sizes.sm.padding} ${formsBaseTheme.sizes.sm.height}`,
@@ -46,26 +46,26 @@ const cronInputTheme = {
46
46
  },
47
47
  // Mode toggle button
48
48
  modeToggleStyle: "inline-flex items-center justify-center rounded-[var(--form-radius)] px-3 py-1.5 text-xs font-medium " +
49
- "cursor-pointer transition-all outline outline-1 outline-[var(--color-border)] " +
49
+ "cursor-pointer transition-all outline-none shadow-[inset_0_0_0_1px_var(--color-border)] " +
50
50
  "text-[var(--color-text-secondary)] bg-white hover:bg-[var(--color-background-secondary)] " +
51
- "dark:bg-[var(--color-neutral-900)] dark:outline-[var(--color-neutral-700)] dark:text-[var(--color-neutral-400)] " +
51
+ "dark:bg-[var(--color-neutral-900)] dark:shadow-[inset_0_0_0_1px_var(--color-neutral-700)] dark:text-[var(--color-neutral-400)] " +
52
52
  "dark:hover:bg-[var(--color-neutral-800)]",
53
53
  // Active mode toggle
54
- modeToggleActiveStyle: "outline-[var(--color-primary)] bg-[var(--color-primary-50)] text-[var(--color-primary)] " +
54
+ modeToggleActiveStyle: "shadow-[inset_0_0_0_1px_var(--color-primary)] bg-[var(--color-primary-50)] text-[var(--color-primary)] " +
55
55
  "hover:bg-[var(--color-primary-50)] " +
56
- "dark:outline-[var(--color-primary-500)] dark:bg-[var(--color-primary-500)]/10 dark:text-[var(--color-primary-400)] " +
56
+ "dark:shadow-[inset_0_0_0_1px_var(--color-primary-500)] dark:bg-[var(--color-primary-500)]/10 dark:text-[var(--color-primary-400)] " +
57
57
  "dark:hover:bg-[var(--color-primary-500)]/15",
58
58
  // Preset button
59
59
  presetButtonStyle: "inline-flex items-center rounded-[var(--form-radius)] px-2.5 py-1 text-xs font-medium " +
60
- "cursor-pointer transition-all outline outline-1 outline-[var(--color-border)] " +
60
+ "cursor-pointer transition-all outline-none shadow-[inset_0_0_0_1px_var(--color-border)] " +
61
61
  "text-[var(--color-text-secondary)] bg-white hover:bg-[var(--color-background-secondary)] " +
62
62
  "hover:text-[var(--color-text-primary)] " +
63
- "dark:bg-[var(--color-neutral-900)] dark:outline-[var(--color-neutral-700)] dark:text-[var(--color-neutral-400)] " +
63
+ "dark:bg-[var(--color-neutral-900)] dark:shadow-[inset_0_0_0_1px_var(--color-neutral-700)] dark:text-[var(--color-neutral-400)] " +
64
64
  "dark:hover:bg-[var(--color-neutral-800)] dark:hover:text-[var(--color-neutral-200)]",
65
65
  // Active preset button
66
- presetButtonActiveStyle: "outline-[var(--color-primary)] bg-[var(--color-primary-50)] text-[var(--color-primary)] " +
66
+ presetButtonActiveStyle: "shadow-[inset_0_0_0_1px_var(--color-primary)] bg-[var(--color-primary-50)] text-[var(--color-primary)] " +
67
67
  "hover:bg-[var(--color-primary-100)] " +
68
- "dark:outline-[var(--color-primary-500)] dark:bg-[var(--color-primary-500)]/10 dark:text-[var(--color-primary-400)]",
68
+ "dark:shadow-[inset_0_0_0_1px_var(--color-primary-500)] dark:bg-[var(--color-primary-500)]/10 dark:text-[var(--color-primary-400)]",
69
69
  // Human-readable description
70
70
  descriptionStyle: "flex items-center gap-2 text-sm text-[var(--color-text-muted)] " +
71
71
  "dark:text-[var(--color-neutral-400)]",
@@ -26,7 +26,7 @@ const DatePickerTrigger = ({ id, disabled, isOpen, state = "default", size = "md
26
26
  // Apply focused styles when open - same pattern as SelectButton
27
27
  const activeFocusState = isOpen
28
28
  ? focusStateStyle ||
29
- "outline-2 outline-primary-600 -outline-offset-1 ring-4 ring-[var(--color-primary)]/10"
29
+ "shadow-[inset_0_0_0_2px_var(--color-primary-600)] ring-4 ring-[var(--color-primary)]/10"
30
30
  : "";
31
31
  return (jsx("div", { className: "relative w-full", children: jsxs("button", { ref: triggerRef, id: id, type: "button", className: cn(baseStyle, sizeStyle, stateStyle, hoverStateStyle, activeFocusState, iconEndPadding, triggerButtonStyle, "text-left", className), onClick: onClick, onFocus: onFocus, onBlur: onBlur, disabled: disabled, "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-label": "Open calendar", "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, children: [children, jsx("span", { className: iconEndStyle, children: jsx(CalendarIcon, { className: "h-4 w-4" }) })] }) }));
32
32
  };
@@ -35,7 +35,7 @@ const dateRangePickerTheme = {
35
35
  mobilePresetsContainerStyle: "sm:hidden px-3 pt-3 pb-1",
36
36
  mobilePresetButtonStyle: "whitespace-nowrap px-3 py-1.5 text-xs font-medium rounded-full transition-colors cursor-pointer shrink-0 " +
37
37
  "bg-[var(--color-background-secondary)] text-[var(--color-text-secondary)] " +
38
- "hover:bg-[var(--color-background-tertiary)] hover:text-[var(--color-text-primary)] " +
38
+ "hover:bg-[var(--color-surface-hover)] hover:text-[var(--color-text-primary)] " +
39
39
  "data-[active=true]:bg-[var(--color-primary-50)] data-[active=true]:text-[var(--color-primary)] " +
40
40
  "dark:bg-[var(--color-neutral-800)] dark:text-[var(--color-neutral-300)] " +
41
41
  "dark:hover:bg-[var(--color-neutral-700)] " +
@@ -24,7 +24,7 @@ const DateRangePickerTrigger = ({ id, disabled, isOpen, state = "default", size
24
24
  const triggerButtonStyle = theme.triggerButtonStyle || "";
25
25
  const activeFocusState = isOpen
26
26
  ? focusStateStyle ||
27
- "outline-2 outline-primary-600 -outline-offset-1 ring-4 ring-[var(--color-primary)]/10"
27
+ "shadow-[inset_0_0_0_2px_var(--color-primary-600)] ring-4 ring-[var(--color-primary)]/10"
28
28
  : "";
29
29
  return (jsx("div", { className: "relative w-full", children: jsxs("button", { ref: triggerRef, id: id, type: "button", className: cn(baseStyle, sizeStyle, stateStyle, hoverStateStyle, activeFocusState, iconEndPadding, triggerButtonStyle, "text-left", className), onClick: onClick, onFocus: onFocus, onBlur: onBlur, disabled: disabled, "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-label": "Open date range picker", "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, children: [children, jsx("span", { className: iconEndStyle, children: jsx(CalendarIcon, { className: "h-4 w-4" }) })] }) }));
30
30
  };
@@ -78,7 +78,6 @@ import '../../core/Sidebar/SidebarContent.js';
78
78
  import '../../core/Sidebar/SidebarFooter.js';
79
79
  import '../../core/Sidebar/SidebarNav.js';
80
80
  import '../../core/Sidebar/SidebarNavGroup.js';
81
- import 'motion/react';
82
81
  import '../../core/Sidebar/SidebarToggle.js';
83
82
  import '../../core/Sidebar/SidebarMobileTrigger.js';
84
83
  import '../../core/Sidebar/SidebarUserProfile.js';
@@ -89,6 +88,7 @@ import '../../core/ContextMenu/ContextMenu.js';
89
88
  import '../../core/ContextMenu/ContextMenu.theme.js';
90
89
  import '../../core/Pill/Pill.js';
91
90
  import '../../core/Icon/Icon.js';
91
+ import '../../core/ImagePlaceholder/ImagePlaceholder.js';
92
92
  import { FormLabel } from '../FormLabel/FormLabel.js';
93
93
 
94
94
  /**
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import React__default, { useState, useEffect } from 'react';
3
3
  import { useReducedMotion, motion, AnimatePresence } from 'motion/react';
4
- import { DocumentIcon, TrashIcon, XMarkIcon, ArrowPathIcon } from '@heroicons/react/24/outline';
4
+ import { DocumentIcon, TrashIcon, ArrowPathIcon, XMarkIcon } from '@heroicons/react/24/outline';
5
5
  import { Icon } from '../../core/Icon/Icon.js';
6
6
  import { fileTypes } from '../../core/Icon/data/fileTypes.js';
7
7
  import { cn } from '../../../utils/cn.js';
@@ -39,27 +39,38 @@ const RadialProgress = ({ progress, status, strokeWidth, trackColor, progressCol
39
39
  setShowRemove(false);
40
40
  }, [isComplete, completionDelay]);
41
41
  const handleClick = () => {
42
- if (isError && onRetry) {
43
- onRetry();
42
+ if (!onRemove)
44
43
  return;
44
+ if (confirmRemove) {
45
+ setConfirmOpen(true);
45
46
  }
46
- if (onRemove) {
47
- if (confirmRemove) {
48
- setConfirmOpen(true);
49
- }
50
- else {
51
- onRemove();
52
- }
47
+ else {
48
+ onRemove();
53
49
  }
54
50
  };
55
51
  const handleConfirm = () => {
56
52
  setConfirmOpen(false);
57
53
  onRemove === null || onRemove === void 0 ? void 0 : onRemove();
58
54
  };
59
- const isClickable = (isError && onRetry) || onRemove;
60
- const ariaLabel = isError && onRetry ? "Retry upload" : onRemove ? "Remove file" : undefined;
55
+ // Uploading/complete: the radial doubles as the cancel/remove target.
56
+ const isClickable = !!onRemove;
57
+ const ariaLabel = onRemove ? "Remove file" : undefined;
58
+ // Confirm popover shared by the radial (cancel/remove) and the error-state delete button.
59
+ const confirmPopover = (trigger, label, offsetValue) => (jsxs(Popover, { isOpen: confirmOpen, onOpenChange: (open) => {
60
+ setConfirmOpen(open);
61
+ if (!open)
62
+ setIsHovered(false);
63
+ }, placement: "bottom-end", offset: offsetValue, triggerType: "click", children: [jsx(Popover.Trigger, { children: trigger }), jsxs(Popover.Body, { className: "flex items-center p-1 border-[0.5px] rounded-xl gap-0.5 bg-opacity-50 backdrop-blur-md", children: [jsx("span", { className: "text-sm font-semibold text-[var(--color-text-secondary)] px-3", children: label }), jsxs("div", { className: "flex gap-1", children: [jsx(Button, { size: "sm", color: "danger", variant: "filled", onClick: handleConfirm, children: "Yes" }), jsx(Button, { size: "sm", variant: "soft", color: "neutral", onClick: () => setConfirmOpen(false), children: "No" })] })] })] }));
61
64
  // Shared remove button used after completion tick
62
65
  const removeButton = (jsx(motion.div, { initial: shouldReduceMotion ? false : REMOVE_BUTTON_ENTER.initial, animate: REMOVE_BUTTON_ENTER.animate, transition: REMOVE_BUTTON_ENTER.transition, className: "shrink-0", children: jsx(Button, { size: "sm", variant: "soft", color: "neutral", "aria-label": "Remove file", iconOnly: true, className: "rounded-full size-8", onClick: confirmRemove ? undefined : () => onRemove === null || onRemove === void 0 ? void 0 : onRemove(), children: jsx(TrashIcon, { className: "size-3.5", strokeWidth: 2 }) }) }, "remove-btn"));
66
+ // Error state: retry + delete buttons (no progress arc/percentage).
67
+ if (isError) {
68
+ const deleteButton = onRemove ? (jsx(Button, { size: "sm", variant: "soft", color: "neutral", "aria-label": "Remove file", iconOnly: true, className: "rounded-full size-8", onClick: confirmRemove ? undefined : () => onRemove(), children: jsx(TrashIcon, { className: "size-3.5", strokeWidth: 2 }) })) : null;
69
+ return (jsxs("div", { className: "flex items-center gap-1 shrink-0", children: [onRetry && (jsx(Button, { size: "sm", variant: "soft", color: "neutral", "aria-label": "Retry upload", iconOnly: true, className: "rounded-full size-8", onClick: () => onRetry(), children: jsx(ArrowPathIcon, { className: "size-3.5", strokeWidth: 2 }) })), deleteButton &&
70
+ (confirmRemove
71
+ ? confirmPopover(deleteButton, "Remove file?", 6)
72
+ : deleteButton)] }));
73
+ }
63
74
  const radialElement = (jsxs("div", { className: cn("relative shrink-0", sizeClass, isClickable && "cursor-pointer"), onMouseEnter: () => setIsHovered(true), onMouseLeave: () => {
64
75
  if (!confirmOpen)
65
76
  setIsHovered(false);
@@ -70,18 +81,14 @@ const RadialProgress = ({ progress, status, strokeWidth, trackColor, progressCol
70
81
  handleClick();
71
82
  }
72
83
  }
73
- : undefined, children: [jsxs("svg", { viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`, className: "w-full h-full -rotate-90", children: [jsx("circle", { cx: CENTER, cy: CENTER, r: radius, fill: "none", stroke: trackColor, strokeWidth: strokeWidth }), jsx(motion.circle, { cx: CENTER, cy: CENTER, r: radius, fill: "none", stroke: progressColor, strokeWidth: strokeWidth, strokeLinecap: "round", strokeDasharray: circumference, initial: { strokeDashoffset: circumference }, animate: { strokeDashoffset: isComplete ? 0 : offset }, transition: shouldReduceMotion ? { duration: 0 } : PROGRESS_SPRING })] }), jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: jsxs(AnimatePresence, { mode: "wait", initial: false, children: [isUploading && !isHovered && (jsx(motion.span, { className: centerTextStyle, ...(shouldReduceMotion ? {} : CROSSFADE), children: progress }, "percent")), isUploading && isHovered && onRemove && (jsx(motion.span, { ...(shouldReduceMotion ? {} : CROSSFADE), children: jsx(XMarkIcon, { className: "size-4 text-[var(--color-text-muted)]", strokeWidth: 2.5 }) }, "close")), isComplete && !showRemove && (jsx(motion.span, { ...(shouldReduceMotion ? {} : CROSSFADE), children: jsx("svg", { viewBox: "0 0 24 24", fill: "none", className: cn("size-4", statusIconColor), children: jsx("path", { d: "M5 13l4.5 4.5L19 7", stroke: "currentColor", strokeWidth: 3.5, strokeLinecap: "round", strokeLinejoin: "round" }) }) }, "check")), isError && (jsx(motion.span, { ...(shouldReduceMotion ? {} : CROSSFADE), children: jsx(ArrowPathIcon, { className: cn("size-3.5", statusIconColor), strokeWidth: 2.5 }) }, "retry"))] }) })] }));
84
+ : undefined, children: [jsxs("svg", { viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`, className: "w-full h-full -rotate-90", children: [jsx("circle", { cx: CENTER, cy: CENTER, r: radius, fill: "none", stroke: trackColor, strokeWidth: strokeWidth }), jsx(motion.circle, { cx: CENTER, cy: CENTER, r: radius, fill: "none", stroke: progressColor, strokeWidth: strokeWidth, strokeLinecap: "round", strokeDasharray: circumference, initial: { strokeDashoffset: circumference }, animate: { strokeDashoffset: isComplete ? 0 : offset }, transition: shouldReduceMotion ? { duration: 0 } : PROGRESS_SPRING })] }), jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: jsxs(AnimatePresence, { mode: "wait", initial: false, children: [isUploading && !isHovered && (jsx(motion.span, { className: centerTextStyle, ...(shouldReduceMotion ? {} : CROSSFADE), children: progress }, "percent")), isUploading && isHovered && onRemove && (jsx(motion.span, { ...(shouldReduceMotion ? {} : CROSSFADE), children: jsx(XMarkIcon, { className: "size-4 text-[var(--color-text-muted)]", strokeWidth: 2.5 }) }, "close")), isComplete && !showRemove && (jsx(motion.span, { ...(shouldReduceMotion ? {} : CROSSFADE), children: jsx("svg", { viewBox: "0 0 24 24", fill: "none", className: cn("size-4", statusIconColor), children: jsx("path", { d: "M5 13l4.5 4.5L19 7", stroke: "currentColor", strokeWidth: 3.5, strokeLinecap: "round", strokeLinejoin: "round" }) }) }, "check"))] }) })] }));
74
85
  // Determine what to render: radial indicator or remove button
75
86
  const showRemoveButton = isComplete && showRemove && onRemove;
76
87
  const triggerElement = showRemoveButton ? removeButton : radialElement;
77
- // No confirm popover needed — return the element directly
88
+ // No confirm popover needed — return the element directly.
78
89
  if (!confirmRemove || !onRemove)
79
90
  return triggerElement;
80
- return (jsxs(Popover, { isOpen: confirmOpen, onOpenChange: (open) => {
81
- setConfirmOpen(open);
82
- if (!open)
83
- setIsHovered(false);
84
- }, placement: "bottom-end", offset: isComplete ? 2 : 6, triggerType: "click", children: [jsx(Popover.Trigger, { children: triggerElement }), jsxs(Popover.Body, { portal: false, className: "flex items-center p-0.5 border-[0.5px] rounded-xl gap-0.5", children: [jsx("span", { className: "text-base font-medium text-[var(--color-text-secondary)] px-3", children: isComplete ? "Remove file?" : "Cancel upload?" }), jsx(Button, { size: "sm", color: "danger", variant: "filled", onClick: handleConfirm, children: "Yes" }), jsx(Button, { size: "sm", variant: "soft", color: "neutral", onClick: () => setConfirmOpen(false), children: "No" })] })] }));
91
+ return confirmPopover(triggerElement, isComplete ? "Remove file?" : "Cancel upload?", isComplete ? 2 : 6);
85
92
  };
86
93
  // --- Main Component ---
87
94
  const FileUploadProgress = React__default.forwardRef(({ items, onRemove, onRetry, showFileSize = true, confirmRemove = true, completionDelay = 1500, className, theme: themeOverrides, ...rest }, ref) => {
@@ -103,7 +110,7 @@ const FileUploadProgress = React__default.forwardRef(({ items, onRemove, onRetry
103
110
  const clampedProgress = Math.min(100, Math.max(0, item.progress));
104
111
  const ext = getFileExtension(item.file.name);
105
112
  const hasFileTypeIcon = ext !== null && isKnownFileType(ext);
106
- return (jsxs("div", { className: (_a = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.itemStyle) !== null && _a !== void 0 ? _a : t.itemStyle, children: [hasFileTypeIcon ? (jsx("span", { className: "shrink-0", children: jsx(Icon, { icon: ext, size: "lg" }) })) : (jsx("span", { className: cn((_b = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.iconContainerStyle) !== null && _b !== void 0 ? _b : t.iconContainerStyle, t.iconSize), children: jsx(DocumentIcon, { className: (_c = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.iconStyle) !== null && _c !== void 0 ? _c : t.iconStyle }) })), jsxs("div", { className: (_d = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.fileInfoStyle) !== null && _d !== void 0 ? _d : t.fileInfoStyle, children: [jsx("p", { className: (_e = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.fileNameStyle) !== null && _e !== void 0 ? _e : t.fileNameStyle, children: item.file.name }), showFileSize && (jsx("p", { className: (_f = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.fileSizeStyle) !== null && _f !== void 0 ? _f : t.fileSizeStyle, children: formatFileSize(item.file.size) })), item.status === "error" && item.error && (jsx("p", { className: (_g = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.errorTextStyle) !== null && _g !== void 0 ? _g : t.errorTextStyle, children: item.error }))] }), jsx(RadialProgress, { progress: clampedProgress, status: item.status, strokeWidth: t.radialStroke, trackColor: (_h = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.radialTrackColor) !== null && _h !== void 0 ? _h : t.radialTrackColor, progressColor: radialProgressColors[item.status], centerTextStyle: (_j = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.radialCenterTextStyle) !== null && _j !== void 0 ? _j : t.radialCenterTextStyle, statusIconColor: statusIconColors[item.status], sizeClass: t.radialSize, shouldReduceMotion: shouldReduceMotion, confirmRemove: confirmRemove, completionDelay: completionDelay, onRemove: onRemove ? () => onRemove(item.id) : undefined, onRetry: onRetry ? () => onRetry(item.id) : undefined })] }, item.id));
113
+ return (jsxs("div", { className: (_a = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.itemStyle) !== null && _a !== void 0 ? _a : t.itemStyle, children: [hasFileTypeIcon ? (jsx("span", { className: "shrink-0", children: jsx(Icon, { icon: ext, size: "lg" }) })) : (jsx("span", { className: cn((_b = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.iconContainerStyle) !== null && _b !== void 0 ? _b : t.iconContainerStyle, t.iconSize), children: jsx(DocumentIcon, { className: (_c = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.iconStyle) !== null && _c !== void 0 ? _c : t.iconStyle }) })), jsxs("div", { className: (_d = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.fileInfoStyle) !== null && _d !== void 0 ? _d : t.fileInfoStyle, children: [jsx("p", { className: (_e = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.fileNameStyle) !== null && _e !== void 0 ? _e : t.fileNameStyle, children: item.file.name }), item.status === "error" && item.error ? (jsx("p", { className: (_f = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.errorTextStyle) !== null && _f !== void 0 ? _f : t.errorTextStyle, children: item.error })) : (showFileSize && (jsx("p", { className: (_g = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.fileSizeStyle) !== null && _g !== void 0 ? _g : t.fileSizeStyle, children: formatFileSize(item.file.size) })))] }), jsx(RadialProgress, { progress: clampedProgress, status: item.status, strokeWidth: t.radialStroke, trackColor: (_h = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.radialTrackColor) !== null && _h !== void 0 ? _h : t.radialTrackColor, progressColor: radialProgressColors[item.status], centerTextStyle: (_j = themeOverrides === null || themeOverrides === void 0 ? void 0 : themeOverrides.radialCenterTextStyle) !== null && _j !== void 0 ? _j : t.radialCenterTextStyle, statusIconColor: statusIconColors[item.status], sizeClass: t.radialSize, shouldReduceMotion: shouldReduceMotion, confirmRemove: confirmRemove, completionDelay: completionDelay, onRemove: onRemove ? () => onRemove(item.id) : undefined, onRetry: onRetry ? () => onRetry(item.id) : undefined })] }, item.id));
107
114
  }) }));
108
115
  });
109
116
  FileUploadProgress.displayName = "FileUploadProgress";
@@ -6,13 +6,13 @@ const fileUploadProgressTheme = {
6
6
  fileInfoStyle: "flex-1 min-w-0",
7
7
  fileNameStyle: "text-sm font-medium text-[var(--color-text-primary)] truncate",
8
8
  fileSizeStyle: "text-xs text-[var(--color-text-muted)]",
9
- radialTrackColor: "var(--color-background-tertiary)",
9
+ radialTrackColor: "var(--color-surface-sunken)",
10
10
  radialProgressColors: {
11
11
  uploading: "var(--color-primary)",
12
12
  complete: "var(--color-success)",
13
13
  error: "var(--color-danger)",
14
14
  },
15
- radialCenterTextStyle: "text-[10px] font-semibold tabular-nums text-[var(--color-text-secondary)]",
15
+ radialCenterTextStyle: "text-xs tracking-tight font-semibold tabular-nums text-[var(--color-text-secondary)]",
16
16
  statusIconColors: {
17
17
  uploading: "",
18
18
  complete: "text-[var(--color-success)]",