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

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 (211) hide show
  1. package/dist/components/ai/CodeBlock/CodeBlock.theme.js +2 -2
  2. package/dist/components/ai/PromptInput/PromptInput.js +4 -0
  3. package/dist/components/ai/PromptInput/VoiceRecorder.js +4 -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 +5 -5
  12. package/dist/components/core/Calendar/Calendar.theme.js +1 -1
  13. package/dist/components/core/Calendar/CalendarMini/CalendarMini.theme.js +1 -1
  14. package/dist/components/core/CommandPalette/CommandItem.js +4 -5
  15. package/dist/components/core/CommandPalette/CommandPalette.js +1 -1
  16. package/dist/components/core/CommandPalette/CommandPalette.theme.js +11 -13
  17. package/dist/components/core/CommandPalette/CommandPalette.types.d.ts +0 -2
  18. package/dist/components/core/ContextMenu/ContextMenu.theme.js +13 -14
  19. package/dist/components/core/DotSeparator/DotSeparator.d.ts +3 -0
  20. package/dist/components/core/DotSeparator/DotSeparator.js +19 -0
  21. package/dist/components/core/DotSeparator/DotSeparator.theme.d.ts +2 -0
  22. package/dist/components/core/DotSeparator/DotSeparator.theme.js +10 -0
  23. package/dist/components/core/DotSeparator/DotSeparator.types.d.ts +25 -0
  24. package/dist/components/core/DotSeparator/index.d.ts +3 -0
  25. package/dist/components/core/Drawer/Drawer.theme.js +2 -2
  26. package/dist/components/core/Dropdown/Dropdown.theme.js +4 -5
  27. package/dist/components/core/Dropdown/DropdownItem.js +1 -1
  28. package/dist/components/core/Dropdown/DropdownMenu.js +1 -1
  29. package/dist/components/core/Empty/Empty.js +1 -1
  30. package/dist/components/core/ImagePlaceholder/ImagePlaceholder.d.ts +14 -0
  31. package/dist/components/core/ImagePlaceholder/ImagePlaceholder.js +28 -0
  32. package/dist/components/core/ImagePlaceholder/ImagePlaceholder.theme.d.ts +6 -0
  33. package/dist/components/core/ImagePlaceholder/ImagePlaceholder.theme.js +8 -0
  34. package/dist/components/core/ImagePlaceholder/ImagePlaceholder.types.d.ts +32 -0
  35. package/dist/components/core/ImagePlaceholder/index.d.ts +2 -0
  36. package/dist/components/core/MenuItem/MenuItem.js +5 -2
  37. package/dist/components/core/MenuItem/MenuItem.theme.d.ts +6 -0
  38. package/dist/components/core/MenuItem/MenuItem.theme.js +19 -16
  39. package/dist/components/core/MenuItem/MenuItem.types.d.ts +2 -0
  40. package/dist/components/core/Message/Message.theme.js +1 -1
  41. package/dist/components/core/Modal/Modal.theme.js +1 -1
  42. package/dist/components/core/NavItem/NavItem.d.ts +1 -1
  43. package/dist/components/core/NavItem/NavItem.js +187 -68
  44. package/dist/components/core/NavItem/NavItem.theme.js +31 -12
  45. package/dist/components/core/NavItem/NavItem.types.d.ts +17 -39
  46. package/dist/components/core/Pagination/Pagination.theme.js +3 -3
  47. package/dist/components/core/Popover/Popover.theme.js +1 -1
  48. package/dist/components/core/Popover/Popover.types.d.ts +6 -2
  49. package/dist/components/core/Popover/PopoverBody.js +10 -3
  50. package/dist/components/core/Progress/Progress.theme.js +1 -1
  51. package/dist/components/core/ScrollArea/ScrollArea.js +2 -2
  52. package/dist/components/core/ScrollArea/ScrollArea.theme.js +1 -1
  53. package/dist/components/core/Segmented/Segmented.js +8 -6
  54. package/dist/components/core/Segmented/Segmented.theme.js +3 -3
  55. package/dist/components/core/Sidebar/Sidebar.d.ts +3 -1
  56. package/dist/components/core/Sidebar/Sidebar.js +53 -16
  57. package/dist/components/core/Sidebar/Sidebar.theme.js +5 -7
  58. package/dist/components/core/Sidebar/Sidebar.types.d.ts +125 -8
  59. package/dist/components/core/Sidebar/SidebarCard.d.ts +25 -0
  60. package/dist/components/core/Sidebar/SidebarCard.js +68 -0
  61. package/dist/components/core/Sidebar/SidebarCard.theme.d.ts +8 -0
  62. package/dist/components/core/Sidebar/SidebarCard.theme.js +18 -0
  63. package/dist/components/core/Sidebar/SidebarContent.js +10 -6
  64. package/dist/components/core/Sidebar/SidebarContext.d.ts +17 -16
  65. package/dist/components/core/Sidebar/SidebarContext.js +43 -20
  66. package/dist/components/core/Sidebar/SidebarFooter.js +4 -6
  67. package/dist/components/core/Sidebar/SidebarHeader.js +12 -9
  68. package/dist/components/core/Sidebar/SidebarLogo.js +39 -8
  69. package/dist/components/core/Sidebar/SidebarNav.js +4 -3
  70. package/dist/components/core/Sidebar/SidebarNavGroup.js +4 -7
  71. package/dist/components/core/Sidebar/SidebarSearch.d.ts +22 -0
  72. package/dist/components/core/Sidebar/SidebarSearch.js +135 -0
  73. package/dist/components/core/Sidebar/SidebarToggle.js +6 -1
  74. package/dist/components/core/Sidebar/SidebarUserProfile.js +33 -17
  75. package/dist/components/core/Sidebar/index.d.ts +4 -3
  76. package/dist/components/core/Skeleton/Skeleton.theme.js +1 -1
  77. package/dist/components/core/Spinner/Spinner.theme.js +1 -1
  78. package/dist/components/core/Tabs/Tabs.js +6 -1
  79. package/dist/components/core/Tabs/Tabs.types.d.ts +2 -0
  80. package/dist/components/core/Tabs/TabsBody.js +5 -3
  81. package/dist/components/core/Tag/Tag.js +29 -5
  82. package/dist/components/core/Tag/Tag.theme.js +14 -9
  83. package/dist/components/core/Tag/Tag.types.d.ts +7 -0
  84. package/dist/components/core/Tooltip/Tooltip.js +1 -1
  85. package/dist/components/core/Tooltip/Tooltip.theme.js +1 -2
  86. package/dist/components/core/index.d.ts +2 -0
  87. package/dist/components/core/index.js +6 -2
  88. package/dist/components/data-display/GanttChart/GanttChart.d.ts +1 -1
  89. package/dist/components/data-display/GanttChart/GanttChart.js +31 -4
  90. package/dist/components/data-display/GanttChart/GanttChart.theme.js +19 -17
  91. package/dist/components/data-display/GanttChart/GanttChart.types.d.ts +19 -0
  92. package/dist/components/data-display/GanttChart/GanttChart.utils.js +1 -1
  93. package/dist/components/data-display/GanttChart/GanttChartPanel.d.ts +1 -1
  94. package/dist/components/data-display/GanttChart/GanttChartPanel.js +3 -3
  95. package/dist/components/data-display/GanttChart/GanttDependencyArrows.js +7 -4
  96. package/dist/components/data-display/GanttChart/GanttMilestone.js +5 -5
  97. package/dist/components/data-display/GanttChart/GanttTableGroupRow.js +1 -1
  98. package/dist/components/data-display/GanttChart/GanttTablePanel.js +1 -1
  99. package/dist/components/data-display/GanttChart/GanttTableTaskRow.js +2 -2
  100. package/dist/components/data-display/GanttChart/GanttTaskBar.js +37 -16
  101. package/dist/components/data-display/GanttChart/GanttTimelineGrid.js +2 -1
  102. package/dist/components/data-display/GanttChart/GanttTimelineHeader.js +35 -11
  103. package/dist/components/data-display/GanttChart/GanttToolbar.js +2 -2
  104. package/dist/components/data-display/GanttChart/hooks/useGanttDrag.js +3 -2
  105. package/dist/components/data-display/GanttChart/index.d.ts +1 -1
  106. package/dist/components/data-display/KPI/KPI.js +13 -3
  107. package/dist/components/data-display/KPI/KPI.theme.js +3 -3
  108. package/dist/components/data-display/Metric/Metric.theme.js +3 -3
  109. package/dist/components/data-display/Table/Table.js +4 -3
  110. package/dist/components/data-display/Table/Table.theme.js +14 -6
  111. package/dist/components/data-display/Table/Table.types.d.ts +15 -0
  112. package/dist/components/data-display/Table/TableColumnManager.js +1 -1
  113. package/dist/components/data-display/Table/index.d.ts +2 -2
  114. package/dist/components/effects/Aurora/Aurora.d.ts +6 -17
  115. package/dist/components/effects/Aurora/Aurora.js +310 -105
  116. package/dist/components/effects/Aurora/Aurora.types.d.ts +6 -0
  117. package/dist/components/effects/InteractiveCharacters/InteractiveCharacters.js +3 -3
  118. package/dist/components/effects/InteractiveCharacters/characters/BlobCharacter.js +13 -4
  119. package/dist/components/effects/InteractiveCharacters/characters/SmallCharacter.js +13 -4
  120. package/dist/components/effects/InteractiveCharacters/characters/TallCharacter.js +14 -4
  121. package/dist/components/effects/MorphingText/MorphingText.js +40 -7
  122. package/dist/components/effects/StripePattern/StripePattern.d.ts +18 -0
  123. package/dist/components/effects/StripePattern/StripePattern.js +54 -0
  124. package/dist/components/effects/StripePattern/StripePattern.types.d.ts +53 -0
  125. package/dist/components/effects/StripePattern/index.d.ts +2 -0
  126. package/dist/components/effects/index.d.ts +2 -0
  127. package/dist/components/effects/index.js +1 -0
  128. package/dist/components/forms/Checkbox/Checkbox.theme.js +1 -1
  129. package/dist/components/forms/Combobox/Combobox.js +1 -1
  130. package/dist/components/forms/Combobox/Combobox.theme.js +2 -4
  131. package/dist/components/forms/CronInput/CronInput.js +1 -1
  132. package/dist/components/forms/CronInput/CronInput.theme.js +22 -31
  133. package/dist/components/forms/DatePicker/DatePicker.theme.js +11 -18
  134. package/dist/components/forms/DatePicker/DatePickerTrigger.js +1 -1
  135. package/dist/components/forms/DateRangePicker/DateRangePicker.theme.js +7 -14
  136. package/dist/components/forms/DateRangePicker/DateRangePickerTrigger.js +1 -1
  137. package/dist/components/forms/FileUpload/FileUpload.animations.d.ts +29 -0
  138. package/dist/components/forms/FileUpload/FileUpload.animations.js +19 -0
  139. package/dist/components/forms/FileUpload/FileUpload.js +88 -49
  140. package/dist/components/forms/FileUpload/FileUpload.theme.d.ts +2 -10
  141. package/dist/components/forms/FileUpload/FileUpload.theme.js +16 -30
  142. package/dist/components/forms/FileUpload/FileUpload.types.d.ts +26 -10
  143. package/dist/components/forms/FileUpload/FileUploadProgress.js +27 -20
  144. package/dist/components/forms/FileUpload/FileUploadProgress.theme.js +2 -2
  145. package/dist/components/forms/Input/Input.theme.js +16 -15
  146. package/dist/components/forms/InputCounter/InputCounter.theme.js +1 -1
  147. package/dist/components/forms/Mention/Mention.js +152 -57
  148. package/dist/components/forms/Mention/Mention.theme.js +16 -23
  149. package/dist/components/forms/Mention/Mention.types.d.ts +12 -12
  150. package/dist/components/forms/Mention/Mention.utils.js +32 -4
  151. package/dist/components/forms/Radio/Radio.theme.js +1 -1
  152. package/dist/components/forms/RichTextEditor/RichTextEditor.d.ts +18 -0
  153. package/dist/components/forms/RichTextEditor/RichTextEditor.js +1231 -236
  154. package/dist/components/forms/RichTextEditor/RichTextEditor.theme.d.ts +53 -1
  155. package/dist/components/forms/RichTextEditor/RichTextEditor.theme.js +99 -25
  156. package/dist/components/forms/RichTextEditor/RichTextEditor.types.d.ts +42 -3
  157. package/dist/components/forms/RichTextEditor/index.d.ts +2 -2
  158. package/dist/components/forms/Select/Select.js +2 -2
  159. package/dist/components/forms/Select/Select.theme.js +3 -3
  160. package/dist/components/forms/Slider/Slider.theme.js +1 -1
  161. package/dist/components/forms/Switch/Switch.theme.js +1 -1
  162. package/dist/components/forms/TimePicker/TimePicker.theme.js +2 -2
  163. package/dist/components/forms/TimePicker/TimePickerContent.js +4 -0
  164. package/dist/components/forms/TimePicker/TimePickerTrigger.js +1 -1
  165. package/dist/components/forms/forms.theme.js +24 -19
  166. package/dist/components/forms/index.js +4 -0
  167. package/dist/components/layout/AppShell/AppShell.d.ts +10 -0
  168. package/dist/components/layout/AppShell/AppShell.js +84 -0
  169. package/dist/components/layout/AppShell/AppShell.theme.d.ts +3 -0
  170. package/dist/components/layout/AppShell/AppShell.theme.js +42 -0
  171. package/dist/components/layout/AppShell/AppShell.types.d.ts +127 -0
  172. package/dist/components/layout/AppShell/AppShellContext.d.ts +14 -0
  173. package/dist/components/layout/AppShell/AppShellContext.js +19 -0
  174. package/dist/components/layout/AppShell/AppShellFooter.d.ts +3 -0
  175. package/dist/components/layout/AppShell/AppShellFooter.js +12 -0
  176. package/dist/components/layout/AppShell/AppShellHeader.d.ts +3 -0
  177. package/dist/components/layout/AppShell/AppShellHeader.js +12 -0
  178. package/dist/components/layout/AppShell/AppShellMain.d.ts +3 -0
  179. package/dist/components/layout/AppShell/AppShellMain.js +19 -0
  180. package/dist/components/layout/AppShell/AppShellRightPanel.d.ts +3 -0
  181. package/dist/components/layout/AppShell/AppShellRightPanel.js +16 -0
  182. package/dist/components/layout/AppShell/AppShellSidebar.d.ts +3 -0
  183. package/dist/components/layout/AppShell/AppShellSidebar.js +16 -0
  184. package/dist/components/layout/AppShell/AppShellTopbar.d.ts +3 -0
  185. package/dist/components/layout/AppShell/AppShellTopbar.js +12 -0
  186. package/dist/components/layout/AppShell/index.d.ts +3 -0
  187. package/dist/components/layout/FormLayout/FormLayout.js +9 -4
  188. package/dist/components/layout/FormLayout/FormLayout.types.d.ts +3 -3
  189. package/dist/components/layout/FormLayout/FormLayoutSection.js +6 -1
  190. package/dist/components/layout/PageLayout/PageLayout.d.ts +2 -2
  191. package/dist/components/layout/PageLayout/PageLayout.js +23 -5
  192. package/dist/components/layout/PageLayout/PageLayout.theme.d.ts +2 -1
  193. package/dist/components/layout/PageLayout/PageLayout.theme.js +35 -6
  194. package/dist/components/layout/PageLayout/PageLayout.types.d.ts +45 -0
  195. package/dist/components/layout/PageLayout/PageLayoutContent.js +6 -4
  196. package/dist/components/layout/PageLayout/PageLayoutHeader.js +3 -3
  197. package/dist/components/layout/PageLayout/PageLayoutSidebar.js +5 -3
  198. package/dist/components/layout/PageLayout/index.d.ts +1 -1
  199. package/dist/components/layout/index.d.ts +1 -0
  200. package/dist/components/layout/index.js +2 -0
  201. package/dist/hooks/useSelectPortal.d.ts +10 -2
  202. package/dist/hooks/useSelectPortal.js +45 -24
  203. package/dist/index.js +8 -2
  204. package/dist/registry.json +10021 -0
  205. package/dist/styles.css +1 -1
  206. package/dist/utils/dateUtils.js +11 -1
  207. package/package.json +4 -2
  208. package/src/global.scss +29 -8
  209. package/src/styles/theme.css +174 -100
  210. package/dist/components/core/Sidebar/SidebarSubmenu.d.ts +0 -7
  211. package/dist/components/core/Sidebar/SidebarSubmenu.js +0 -12
@@ -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
@@ -100,7 +100,7 @@ const ComboboxOptions = ({ isOpen, onClose, triggerRef, portal, placement, offse
100
100
  }, children: isCreateOption ? (jsxs("span", { className: "flex items-center gap-1", children: [jsx(PlusIcon, { className: "size-4 shrink-0", strokeWidth: 2 }), jsx("span", { className: "block truncate", children: option.label })] })) : (jsx("span", { className: "block truncate", children: option.label })) }, option.id));
101
101
  }), filteredOptions.length > 100 && (jsxs("div", { className: "px-3 py-2 text-xs text-[var(--color-text-muted)] text-center border-t border-[var(--color-border)]", children: ["Showing 100 of ", filteredOptions.length, " results \u2014 refine your search"] }))] })) })) }));
102
102
  if (portal && isClient) {
103
- return createPortal(jsx("div", { className: isDarkMode ? "dark" : undefined, children: optionsContent }), document.body);
103
+ return createPortal(jsx("div", { "data-flikkui-portal": "", className: isDarkMode ? "dark" : undefined, children: optionsContent }), document.body);
104
104
  }
105
105
  return optionsContent;
106
106
  };
@@ -28,14 +28,12 @@ const comboboxTheme = {
28
28
  focusStates: formsBaseTheme.focusStates,
29
29
  // Icon positioning styles
30
30
  iconStartStyle: formsBaseTheme.iconStyles.left,
31
- iconEndStyle: "absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none text-[var(--color-text-muted)] " +
32
- "dark:text-[var(--color-neutral-500)]",
31
+ iconEndStyle: "absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none text-[var(--color-text-muted)]",
33
32
  // Icon padding configuration
34
33
  iconPadding: formsBaseTheme.iconStyles.padding,
35
34
  // Clear button styles
36
35
  clearButtonStyle: "absolute inset-y-0 right-0 flex items-center pr-2 cursor-pointer " +
37
- "text-[var(--color-text-muted)] hover:text-[var(--color-text-primary)] transition-colors z-10 " +
38
- "dark:text-[var(--color-neutral-500)] dark:hover:text-[var(--color-neutral-200)]",
36
+ "text-[var(--color-text-muted)] hover:text-[var(--color-text-primary)] transition-colors z-10",
39
37
  clearIconStyle: "size-4",
40
38
  // Dropdown styles - matches Select component for consistency
41
39
  dropdownStyle: formsBaseTheme.dropdownStyles.container + " py-1",
@@ -104,7 +104,7 @@ const CronInput = React__default.forwardRef(({ value: controlledValue, defaultVa
104
104
  const showVisual = mode === "visual" || (mode === "both" && activeMode === "visual");
105
105
  const showRaw = mode === "raw" || (mode === "both" && activeMode === "raw");
106
106
  const helperId = `${generatedId}-helper`;
107
- return (jsxs("div", { ref: ref, className: cn(theme.baseStyle, className), role: "group", "aria-label": label || "Cron expression builder", ...props, children: [label && (jsx(FormLabel, { htmlFor: `${generatedId}-cron`, state: isDisabled ? "disabled" : isInvalid ? "invalid" : "default", children: label })), mode === "both" && (jsxs("div", { className: "flex items-center gap-1.5", children: [jsxs("button", { type: "button", onClick: () => setActiveMode("visual"), disabled: isDisabled, className: cn(theme.modeToggleStyle, activeMode === "visual" && theme.modeToggleActiveStyle), "aria-pressed": activeMode === "visual", children: [jsx(CalendarIcon, { className: "w-3.5 h-3.5 mr-1", "aria-hidden": "true" }), "Visual"] }), jsxs("button", { type: "button", onClick: () => setActiveMode("raw"), disabled: isDisabled, className: cn(theme.modeToggleStyle, activeMode === "raw" && theme.modeToggleActiveStyle), "aria-pressed": activeMode === "raw", children: [jsx(ClockIcon, { className: "w-3.5 h-3.5 mr-1", "aria-hidden": "true" }), "Cron"] })] })), showPresets && (jsxs("div", { children: [jsx("div", { className: cn(theme.sectionHeadingStyle, "mb-1.5"), children: "Presets" }), jsx("div", { className: "flex flex-wrap gap-1.5", children: CRON_PRESETS.map((preset) => (jsx("button", { type: "button", onClick: () => handlePresetClick(preset.value), disabled: isDisabled, className: cn(theme.presetButtonStyle, activePreset === preset.value && theme.presetButtonActiveStyle), title: preset.description, "aria-pressed": activePreset === preset.value, children: preset.label }, preset.value))) })] })), showVisual && (jsxs("div", { className: cn(theme.builderStyle, isInvalid && "ring-1 ring-[var(--color-danger)] rounded-[var(--form-radius)]"), children: [jsx(FieldSelect, { label: "Minute", value: fields.minute, options: minuteOptions, onChange: (v) => handleFieldChange("minute", v), disabled: isDisabled, size: size }), jsx(FieldSelect, { label: "Hour", value: fields.hour, options: hourOptions, onChange: (v) => handleFieldChange("hour", v), disabled: isDisabled, size: size }), jsx(FieldSelect, { label: "Day of Month", value: fields.dayOfMonth, options: dayOfMonthOptions, onChange: (v) => handleFieldChange("dayOfMonth", v), disabled: isDisabled, size: size }), jsx(FieldSelect, { label: "Month", value: fields.month, options: monthOptions, onChange: (v) => handleFieldChange("month", v), disabled: isDisabled, size: size }), jsx(FieldSelect, { label: "Day of Week", value: fields.dayOfWeek, options: dayOfWeekOptions, onChange: (v) => handleFieldChange("dayOfWeek", v), disabled: isDisabled, size: size })] })), showRaw && (jsxs("div", { children: [jsx("div", { className: cn(theme.sectionHeadingStyle, "mb-1.5"), children: "Cron Expression" }), jsx("input", { type: "text", value: rawInput, onChange: handleRawInputChange, onBlur: handleRawInputBlur, onKeyDown: handleRawKeyDown, disabled: isDisabled, placeholder: "* * * * *", className: cn(theme.rawInputStyle, theme.rawInputSizes[size], isInvalid && "border-[var(--color-danger)] focus:border-[var(--color-danger)] focus:ring-[var(--color-danger)]"), id: `${generatedId}-cron`, "aria-label": "Cron expression", "aria-invalid": isInvalid || !validateCron(rawInput), "aria-describedby": helperText ? helperId : undefined, spellCheck: false, autoComplete: "off" }), !validateCron(rawInput) && rawInput !== cronValue && (jsx("div", { className: cn(theme.errorStyle, "mt-1"), children: "Invalid cron expression. Format: minute hour day month weekday" }))] })), showVisual && !showRaw && (jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: cn(theme.fieldLabelStyle, "shrink-0"), children: "Expression:" }), jsx("code", { className: cn("font-mono text-sm px-2 py-1 rounded-[var(--form-radius)]", "bg-[var(--color-background-secondary)] text-[var(--color-text-primary)]", "dark:bg-[var(--color-neutral-800)] dark:text-[var(--color-neutral-200)]"), children: cronValue })] })), showDescription && isValid && (jsxs("div", { className: theme.descriptionStyle, children: [jsx(ClockIcon, { className: "w-4 h-4 shrink-0", "aria-hidden": "true" }), jsx("span", { children: description })] })), showNextRuns && isValid && nextRuns.length > 0 && (jsxs("div", { className: theme.nextRunsStyle, children: [jsx("div", { className: cn(theme.sectionHeadingStyle, "mb-1"), children: "Next runs" }), nextRuns.map((date, index) => (jsxs("div", { className: theme.nextRunItemStyle, children: [jsx(CalendarIcon, { className: "w-3.5 h-3.5 shrink-0", "aria-hidden": "true" }), jsx("span", { children: formatNextRun(date) })] }, index)))] })), helperText && (jsx("div", { id: helperId, className: cn("text-sm mt-1", isInvalid
107
+ return (jsxs("div", { ref: ref, className: cn(theme.baseStyle, className), role: "group", "aria-label": label || "Cron expression builder", ...props, children: [label && (jsx(FormLabel, { htmlFor: `${generatedId}-cron`, state: isDisabled ? "disabled" : isInvalid ? "invalid" : "default", children: label })), mode === "both" && (jsxs("div", { className: "flex items-center gap-1.5", children: [jsxs("button", { type: "button", onClick: () => setActiveMode("visual"), disabled: isDisabled, className: cn(theme.modeToggleStyle, activeMode === "visual" && theme.modeToggleActiveStyle), "aria-pressed": activeMode === "visual", children: [jsx(CalendarIcon, { className: "w-3.5 h-3.5 mr-1", "aria-hidden": "true" }), "Visual"] }), jsxs("button", { type: "button", onClick: () => setActiveMode("raw"), disabled: isDisabled, className: cn(theme.modeToggleStyle, activeMode === "raw" && theme.modeToggleActiveStyle), "aria-pressed": activeMode === "raw", children: [jsx(ClockIcon, { className: "w-3.5 h-3.5 mr-1", "aria-hidden": "true" }), "Cron"] })] })), showPresets && (jsxs("div", { children: [jsx("div", { className: cn(theme.sectionHeadingStyle, "mb-1.5"), children: "Presets" }), jsx("div", { className: "flex flex-wrap gap-1.5", children: CRON_PRESETS.map((preset) => (jsx("button", { type: "button", onClick: () => handlePresetClick(preset.value), disabled: isDisabled, className: cn(theme.presetButtonStyle, activePreset === preset.value && theme.presetButtonActiveStyle), title: preset.description, "aria-pressed": activePreset === preset.value, children: preset.label }, preset.value))) })] })), showVisual && (jsxs("div", { className: cn(theme.builderStyle, isInvalid && "ring-1 ring-[var(--color-danger)] rounded-[var(--form-radius)]"), children: [jsx(FieldSelect, { label: "Minute", value: fields.minute, options: minuteOptions, onChange: (v) => handleFieldChange("minute", v), disabled: isDisabled, size: size }), jsx(FieldSelect, { label: "Hour", value: fields.hour, options: hourOptions, onChange: (v) => handleFieldChange("hour", v), disabled: isDisabled, size: size }), jsx(FieldSelect, { label: "Day of Month", value: fields.dayOfMonth, options: dayOfMonthOptions, onChange: (v) => handleFieldChange("dayOfMonth", v), disabled: isDisabled, size: size }), jsx(FieldSelect, { label: "Month", value: fields.month, options: monthOptions, onChange: (v) => handleFieldChange("month", v), disabled: isDisabled, size: size }), jsx(FieldSelect, { label: "Day of Week", value: fields.dayOfWeek, options: dayOfWeekOptions, onChange: (v) => handleFieldChange("dayOfWeek", v), disabled: isDisabled, size: size })] })), showRaw && (jsxs("div", { children: [jsx("div", { className: cn(theme.sectionHeadingStyle, "mb-1.5"), children: "Cron Expression" }), jsx("input", { type: "text", value: rawInput, onChange: handleRawInputChange, onBlur: handleRawInputBlur, onKeyDown: handleRawKeyDown, disabled: isDisabled, placeholder: "* * * * *", className: cn(theme.rawInputStyle, theme.rawInputSizes[size], isInvalid && "border-[var(--color-danger)] focus:border-[var(--color-danger)] focus:ring-[var(--color-danger)]"), id: `${generatedId}-cron`, "aria-label": "Cron expression", "aria-invalid": isInvalid || !validateCron(rawInput), "aria-describedby": helperText ? helperId : undefined, spellCheck: false, autoComplete: "off" }), !validateCron(rawInput) && rawInput !== cronValue && (jsx("div", { className: cn(theme.errorStyle, "mt-1"), children: "Invalid cron expression. Format: minute hour day month weekday" }))] })), showVisual && !showRaw && (jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: cn(theme.fieldLabelStyle, "shrink-0"), children: "Expression:" }), jsx("code", { className: cn("font-mono text-sm px-2 py-1 rounded-[var(--form-radius)]", "bg-[var(--color-surface-sunken)] text-[var(--color-text-primary)]"), children: cronValue })] })), showDescription && isValid && (jsxs("div", { className: theme.descriptionStyle, children: [jsx(ClockIcon, { className: "w-4 h-4 shrink-0", "aria-hidden": "true" }), jsx("span", { children: description })] })), showNextRuns && isValid && nextRuns.length > 0 && (jsxs("div", { className: theme.nextRunsStyle, children: [jsx("div", { className: cn(theme.sectionHeadingStyle, "mb-1"), children: "Next runs" }), nextRuns.map((date, index) => (jsxs("div", { className: theme.nextRunItemStyle, children: [jsx(CalendarIcon, { className: "w-3.5 h-3.5 shrink-0", "aria-hidden": "true" }), jsx("span", { children: formatNextRun(date) })] }, index)))] })), helperText && (jsx("div", { id: helperId, className: cn("text-sm mt-1", isInvalid
108
108
  ? "text-[var(--color-danger)]"
109
109
  : "text-[var(--color-text-muted)]"), children: helperText }))] }));
110
110
  });
@@ -8,21 +8,20 @@ const cronInputTheme = {
8
8
  // Outer wrapper
9
9
  baseStyle: "relative w-full flex flex-col gap-3",
10
10
  // Label
11
- labelStyle: "text-sm font-medium text-[var(--color-text-primary)] dark:text-[var(--color-neutral-200)]",
11
+ labelStyle: "text-sm font-medium text-[var(--color-text-primary)]",
12
12
  // Visual builder grid
13
13
  builderStyle: "grid grid-cols-5 gap-2",
14
14
  // Individual field group
15
15
  fieldGroupStyle: "flex flex-col gap-1",
16
16
  // Field label
17
- fieldLabelStyle: "text-xs font-medium text-[var(--color-text-secondary)] dark:text-[var(--color-neutral-400)]",
17
+ fieldLabelStyle: "text-xs font-medium text-[var(--color-text-secondary)]",
18
18
  // Select dropdown
19
- fieldSelectStyle: "w-full rounded-[var(--form-radius)] outline outline-1 outline-[var(--color-border)] " +
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 " +
19
+ fieldSelectStyle: "w-full rounded-[var(--form-radius)] outline-none shadow-[inset_0_0_0_1px_var(--color-border)] " +
20
+ "bg-[var(--color-surface)] text-[var(--color-text-primary)] cursor-pointer transition-all " +
21
+ "focus:shadow-[inset_0_0_0_1px_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:focus:shadow-[inset_0_0_0_1px_var(--color-primary-500)] dark:focus:ring-[var(--color-primary-500)]/20",
26
25
  // Size variants for field selects
27
26
  fieldSelectSizes: {
28
27
  sm: `${formsBaseTheme.sizes.sm.text} ${formsBaseTheme.sizes.sm.padding} ${formsBaseTheme.sizes.sm.height}`,
@@ -30,14 +29,13 @@ const cronInputTheme = {
30
29
  lg: `${formsBaseTheme.sizes.lg.text} ${formsBaseTheme.sizes.lg.padding} ${formsBaseTheme.sizes.lg.height}`,
31
30
  },
32
31
  // Raw input field
33
- rawInputStyle: "w-full rounded-[var(--form-radius)] outline outline-1 outline-[var(--color-border)] " +
34
- "bg-white text-[var(--color-text-primary)] font-mono transition-all " +
32
+ rawInputStyle: "w-full rounded-[var(--form-radius)] outline-none shadow-[inset_0_0_0_1px_var(--color-border)] " +
33
+ "bg-[var(--color-surface)] text-[var(--color-text-primary)] font-mono transition-all " +
35
34
  "placeholder:text-[var(--color-text-placeholder)] focus:outline-none " +
36
- "focus:outline-2 focus:outline-[var(--color-primary-600)] focus:-outline-offset-1 " +
35
+ "focus:shadow-[inset_0_0_0_1px_var(--color-primary-600)] " +
37
36
  "focus:ring-4 focus:ring-[var(--color-primary)]/10 " +
38
37
  "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",
38
+ "dark:focus:shadow-[inset_0_0_0_1px_var(--color-primary-500)] dark:focus:ring-[var(--color-primary-500)]/20",
41
39
  // Size variants for raw input
42
40
  rawInputSizes: {
43
41
  sm: `${formsBaseTheme.sizes.sm.text} ${formsBaseTheme.sizes.sm.padding} ${formsBaseTheme.sizes.sm.height}`,
@@ -46,37 +44,30 @@ const cronInputTheme = {
46
44
  },
47
45
  // Mode toggle button
48
46
  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)] " +
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)] " +
52
- "dark:hover:bg-[var(--color-neutral-800)]",
47
+ "cursor-pointer transition-all outline-none shadow-[inset_0_0_0_1px_var(--color-border)] " +
48
+ "text-[var(--color-text-secondary)] bg-[var(--color-surface)] hover:bg-[var(--color-surface-hover)]",
53
49
  // Active mode toggle
54
- modeToggleActiveStyle: "outline-[var(--color-primary)] bg-[var(--color-primary-50)] text-[var(--color-primary)] " +
50
+ modeToggleActiveStyle: "shadow-[inset_0_0_0_1px_var(--color-primary)] bg-[var(--color-primary-50)] text-[var(--color-primary)] " +
55
51
  "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)] " +
52
+ "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
53
  "dark:hover:bg-[var(--color-primary-500)]/15",
58
54
  // Preset button
59
55
  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)] " +
61
- "text-[var(--color-text-secondary)] bg-white hover:bg-[var(--color-background-secondary)] " +
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)] " +
64
- "dark:hover:bg-[var(--color-neutral-800)] dark:hover:text-[var(--color-neutral-200)]",
56
+ "cursor-pointer transition-all outline-none shadow-[inset_0_0_0_1px_var(--color-border)] " +
57
+ "text-[var(--color-text-secondary)] bg-[var(--color-surface)] hover:bg-[var(--color-surface-hover)] " +
58
+ "hover:text-[var(--color-text-primary)]",
65
59
  // Active preset button
66
- presetButtonActiveStyle: "outline-[var(--color-primary)] bg-[var(--color-primary-50)] text-[var(--color-primary)] " +
60
+ presetButtonActiveStyle: "shadow-[inset_0_0_0_1px_var(--color-primary)] bg-[var(--color-primary-50)] text-[var(--color-primary)] " +
67
61
  "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)]",
62
+ "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
63
  // Human-readable description
70
- descriptionStyle: "flex items-center gap-2 text-sm text-[var(--color-text-muted)] " +
71
- "dark:text-[var(--color-neutral-400)]",
64
+ descriptionStyle: "flex items-center gap-2 text-sm text-[var(--color-text-muted)]",
72
65
  // Next runs container
73
66
  nextRunsStyle: "flex flex-col gap-1",
74
67
  // Individual next run item
75
- nextRunItemStyle: "flex items-center gap-2 text-xs text-[var(--color-text-muted)] " +
76
- "dark:text-[var(--color-neutral-400)]",
68
+ nextRunItemStyle: "flex items-center gap-2 text-xs text-[var(--color-text-muted)]",
77
69
  // Section heading
78
- sectionHeadingStyle: "text-xs font-medium text-[var(--color-text-secondary)] uppercase tracking-wide " +
79
- "dark:text-[var(--color-neutral-400)]",
70
+ sectionHeadingStyle: "text-xs font-medium text-[var(--color-text-secondary)] uppercase tracking-wide",
80
71
  // Validation error
81
72
  errorStyle: "text-xs text-[var(--color-danger)] dark:text-[var(--color-danger-400)]",
82
73
  };
@@ -10,8 +10,8 @@ import { formsBaseTheme } from '../forms.theme.js';
10
10
  const datePickerTheme = {
11
11
  containerStyle: formsBaseTheme.wrapperStyle,
12
12
  baseStyle: formsBaseTheme.inputGroupBaseStyle + " justify-between cursor-pointer",
13
- // Trigger button style - bg-white for light mode; dark mode uses neutral-900
14
- triggerButtonStyle: "w-full cursor-pointer bg-white dark:bg-[var(--color-neutral-900)]",
13
+ // Trigger button style - surface flips automatically between light/dark
14
+ triggerButtonStyle: "w-full cursor-pointer bg-[var(--color-surface)]",
15
15
  // Placeholder text style - matches Input placeholder styling
16
16
  placeholderTextStyle: "text-[var(--color-text-placeholder)]",
17
17
  // Selected value text style
@@ -26,23 +26,16 @@ const datePickerTheme = {
26
26
  triggerFocusStates: formsBaseTheme.focusStates,
27
27
  iconEndStyle: formsBaseTheme.iconStyles.right,
28
28
  iconEndPadding: formsBaseTheme.iconStyles.padding.right,
29
- // Dropdown body - with dark mode support
30
- bodyStyle: "min-w-fit max-w-none bg-white border border-[var(--color-border)] rounded-[var(--popover-radius)] shadow-real-xl p-0 overflow-hidden z-[1000] fixed " +
31
- "dark:bg-[var(--color-neutral-900)] dark:border-[var(--color-neutral-700)]",
32
- bodyWithPresetsStyle: "flex flex-col sm:flex-row w-fit max-w-[calc(100vw-2rem)] sm:max-w-none bg-white border border-[var(--color-border)] rounded-[var(--popover-radius)] shadow-lg p-0 overflow-hidden z-[1000] fixed " +
33
- "dark:bg-[var(--color-neutral-900)] dark:border-[var(--color-neutral-700)]",
34
- // Presets sidebar - with dark mode support
35
- presetsContainerStyle: "flex flex-col gap-1 p-3 border-b sm:border-b-0 sm:border-r border-[var(--color-border)] bg-[var(--color-neutral-50)] sm:min-w-[180px] " +
36
- "dark:bg-[var(--color-neutral-800)] dark:border-[var(--color-neutral-700)]",
37
- // Preset button - with dark mode support
29
+ // Dropdown body - floating overlay surface flips automatically
30
+ bodyStyle: "min-w-fit max-w-none bg-[var(--color-surface-overlay)] border border-[var(--color-border)] rounded-[var(--popover-radius)] shadow-real-xl p-0 overflow-hidden z-[1000] fixed",
31
+ bodyWithPresetsStyle: "flex flex-col sm:flex-row w-fit max-w-[calc(100vw-2rem)] sm:max-w-none bg-[var(--color-surface-overlay)] border border-[var(--color-border)] rounded-[var(--popover-radius)] shadow-lg p-0 overflow-hidden z-[1000] fixed",
32
+ // Presets sidebar - recessed sunken panel flips automatically
33
+ presetsContainerStyle: "flex flex-col gap-1 p-3 border-b sm:border-b-0 sm:border-r border-[var(--color-border)] bg-[var(--color-surface-sunken)] sm:min-w-[180px]",
34
+ // Preset button - surface hover/active fills flip automatically
38
35
  presetButtonStyle: "w-full text-left px-3 py-2 text-sm rounded-[calc(var(--radius-base)*0.75)] transition-colors cursor-pointer " +
39
- "text-[var(--color-text-secondary)] hover:bg-white hover:text-[var(--color-text-primary)] " +
40
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-offset-2 " +
41
- "data-[active=true]:bg-white data-[active=true]:text-[var(--color-text-primary)] data-[active=true]:font-medium " +
42
- // Dark mode
43
- "dark:text-[var(--color-neutral-400)] dark:hover:bg-[var(--color-neutral-700)] dark:hover:text-[var(--color-neutral-200)] " +
44
- "dark:data-[active=true]:bg-[var(--color-neutral-700)] dark:data-[active=true]:text-[var(--color-neutral-100)] " +
45
- "dark:focus-visible:ring-offset-[var(--color-neutral-800)]",
36
+ "text-[var(--color-text-secondary)] hover:bg-[var(--color-surface-hover)] hover:text-[var(--color-text-primary)] " +
37
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-surface-sunken)] " +
38
+ "data-[active=true]:bg-[var(--color-surface)] data-[active=true]:text-[var(--color-text-primary)] data-[active=true]:font-medium",
46
39
  helperTextStyle: formsBaseTheme.helperText,
47
40
  helperTextStates: {
48
41
  default: "text-[var(--color-text-muted)] 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_1px_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
  };
@@ -6,7 +6,7 @@ import { formsBaseTheme } from '../forms.theme.js';
6
6
  const dateRangePickerTheme = {
7
7
  containerStyle: formsBaseTheme.wrapperStyle,
8
8
  baseStyle: formsBaseTheme.inputGroupBaseStyle + " justify-between cursor-pointer",
9
- triggerButtonStyle: "w-full cursor-pointer bg-white dark:bg-[var(--color-neutral-900)]",
9
+ triggerButtonStyle: "w-full cursor-pointer bg-[var(--color-surface)]",
10
10
  placeholderTextStyle: "text-[var(--color-text-placeholder)]",
11
11
  valueTextStyle: "text-[var(--color-text-primary)]",
12
12
  triggerSizes: {
@@ -19,26 +19,19 @@ const dateRangePickerTheme = {
19
19
  triggerFocusStates: formsBaseTheme.focusStates,
20
20
  iconEndStyle: formsBaseTheme.iconStyles.right,
21
21
  iconEndPadding: formsBaseTheme.iconStyles.padding.right,
22
- bodyStyle: "flex flex-col sm:flex-row w-fit max-w-[calc(100vw-2rem)] sm:max-w-none bg-white border border-[var(--color-border)] rounded-[var(--popover-radius)] shadow-lg p-0 overflow-hidden z-[1000] fixed " +
23
- "dark:bg-[var(--color-neutral-900)] dark:border-[var(--color-neutral-700)]",
24
- presetsContainerStyle: "hidden sm:flex flex-col gap-1 p-3 sm:border-r border-[var(--color-border)] bg-[var(--color-neutral-50)] sm:min-w-[180px] " +
25
- "dark:bg-[var(--color-neutral-800)] ",
22
+ bodyStyle: "flex flex-col sm:flex-row w-fit max-w-[calc(100vw-2rem)] sm:max-w-none bg-[var(--color-surface-overlay)] border border-[var(--color-border)] rounded-[var(--popover-radius)] shadow-lg p-0 overflow-hidden z-[1000] fixed",
23
+ presetsContainerStyle: "hidden sm:flex flex-col gap-1 p-3 sm:border-r border-[var(--color-border)] bg-[var(--color-surface-sunken)] sm:min-w-[180px]",
26
24
  presetButtonStyle: "w-full text-left px-3 py-2 text-sm font-medium rounded-[calc(var(--radius-base)*0.75)] transition-colors cursor-pointer " +
27
25
  "flex items-center justify-between gap-2 " +
28
- "text-[var(--color-text-secondary)] hover:bg-white hover:text-[var(--color-text-primary)] " +
29
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-offset-2 " +
30
- "data-[active=true]:bg-white data-[active=true]:text-[var(--color-text-primary)] data-[active=true]:font-medium " +
31
- "dark:hover:bg-[var(--color-neutral-700)] " +
32
- "dark:data-[active=true]:bg-[var(--color-neutral-700)] dark:data-[active=true]:text-[var(--color-neutral-100)] " +
33
- "dark:focus-visible:ring-offset-[var(--color-neutral-800)]",
26
+ "text-[var(--color-text-secondary)] hover:bg-[var(--color-surface-hover)] hover:text-[var(--color-text-primary)] " +
27
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-primary)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-surface-sunken)] " +
28
+ "data-[active=true]:bg-[var(--color-surface)] data-[active=true]:text-[var(--color-text-primary)] data-[active=true]:font-medium",
34
29
  presetCheckmarkStyle: "size-4 text-[var(--color-primary)] shrink-0",
35
30
  mobilePresetsContainerStyle: "sm:hidden px-3 pt-3 pb-1",
36
31
  mobilePresetButtonStyle: "whitespace-nowrap px-3 py-1.5 text-xs font-medium rounded-full transition-colors cursor-pointer shrink-0 " +
37
32
  "bg-[var(--color-background-secondary)] text-[var(--color-text-secondary)] " +
38
- "hover:bg-[var(--color-background-tertiary)] hover:text-[var(--color-text-primary)] " +
33
+ "hover:bg-[var(--color-surface-hover)] hover:text-[var(--color-text-primary)] " +
39
34
  "data-[active=true]:bg-[var(--color-primary-50)] data-[active=true]:text-[var(--color-primary)] " +
40
- "dark:bg-[var(--color-neutral-800)] dark:text-[var(--color-neutral-300)] " +
41
- "dark:hover:bg-[var(--color-neutral-700)] " +
42
35
  "dark:data-[active=true]:bg-[var(--color-primary-950)] dark:data-[active=true]:text-[var(--color-primary-300)]",
43
36
  mobileRangeDisplayStyle: "sm:hidden text-xs text-center py-2 text-[var(--color-text-secondary)] dark:text-[var(--color-neutral-400)]",
44
37
  helperTextStyle: formsBaseTheme.helperText,
@@ -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_1px_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
  };
@@ -0,0 +1,29 @@
1
+ /** Spring used for thumbnail enter and for the layout reflow when items are removed. */
2
+ export declare const PREVIEW_LAYOUT_SPRING: {
3
+ type: "spring";
4
+ stiffness: number;
5
+ damping: number;
6
+ mass: number;
7
+ };
8
+ /**
9
+ * Enter / exit variants for a preview thumbnail.
10
+ * Exit shrinks + fades so the surrounding items can flow into the gap (driven
11
+ * by `layout` on each item). Pair with `AnimatePresence`.
12
+ */
13
+ export declare const PREVIEW_ITEM: {
14
+ initial: {
15
+ opacity: number;
16
+ scale: number;
17
+ };
18
+ animate: {
19
+ opacity: number;
20
+ scale: number;
21
+ };
22
+ exit: {
23
+ opacity: number;
24
+ scale: number;
25
+ transition: {
26
+ duration: number;
27
+ };
28
+ };
29
+ };
@@ -0,0 +1,19 @@
1
+ /** Spring used for thumbnail enter and for the layout reflow when items are removed. */
2
+ const PREVIEW_LAYOUT_SPRING = {
3
+ type: "spring",
4
+ stiffness: 500,
5
+ damping: 38,
6
+ mass: 0.8,
7
+ };
8
+ /**
9
+ * Enter / exit variants for a preview thumbnail.
10
+ * Exit shrinks + fades so the surrounding items can flow into the gap (driven
11
+ * by `layout` on each item). Pair with `AnimatePresence`.
12
+ */
13
+ const PREVIEW_ITEM = {
14
+ initial: { opacity: 0, scale: 0.8 },
15
+ animate: { opacity: 1, scale: 1 },
16
+ exit: { opacity: 0, scale: 0.8, transition: { duration: 0.15 } },
17
+ };
18
+
19
+ export { PREVIEW_ITEM, PREVIEW_LAYOUT_SPRING };