@flikk/ui 1.0.0-beta.11 → 1.0.0-beta.13

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 (220) hide show
  1. package/dist/components/ai/ApprovalCard/ApprovalCard.js +1 -1
  2. package/dist/components/ai/MessageHistory/MessageHistory.js +1 -0
  3. package/dist/components/ai/PromptInput/PromptInput.js +7 -125
  4. package/dist/components/ai/PromptInput/VoiceRecorder.js +0 -77
  5. package/dist/components/ai/StreamingResponse/StreamingResponse.js +1 -0
  6. package/dist/components/ai/StreamingResponse/StreamingResponse.types.d.ts +7 -7
  7. package/dist/components/ai/index.js +1 -0
  8. package/dist/components/core/Accordion/Accordion.d.ts +1 -1
  9. package/dist/components/core/Accordion/Accordion.js +2 -2
  10. package/dist/components/core/Accordion/Accordion.theme.d.ts +2 -2
  11. package/dist/components/core/Accordion/Accordion.theme.js +4 -4
  12. package/dist/components/core/Accordion/Accordion.types.d.ts +19 -20
  13. package/dist/components/core/Accordion/AccordionBody.d.ts +3 -0
  14. package/dist/components/core/Accordion/{AccordionContent.js → AccordionBody.js} +4 -4
  15. package/dist/components/core/Accordion/AccordionItem.js +1 -1
  16. package/dist/components/core/Accordion/AccordionTrigger.js +14 -7
  17. package/dist/components/core/Accordion/index.d.ts +2 -2
  18. package/dist/components/core/Alert/Alert.js +5 -1
  19. package/dist/components/core/Alert/Alert.types.d.ts +4 -4
  20. package/dist/components/core/Avatar/Avatar.js +22 -18
  21. package/dist/components/core/Avatar/Avatar.theme.js +1 -1
  22. package/dist/components/core/Avatar/Avatar.types.d.ts +9 -8
  23. package/dist/components/core/AvatarGroup/AvatarGroup.js +2 -2
  24. package/dist/components/core/Badge/Badge.js +7 -5
  25. package/dist/components/core/Badge/Badge.theme.js +11 -4
  26. package/dist/components/core/Badge/Badge.types.d.ts +2 -2
  27. package/dist/components/core/Breadcrumbs/Breadcrumbs.js +7 -3
  28. package/dist/components/core/Breadcrumbs/Breadcrumbs.types.d.ts +1 -1
  29. package/dist/components/core/Button/Button.js +2 -8
  30. package/dist/components/core/Button/Button.theme.js +7 -7
  31. package/dist/components/core/Calendar/Calendar.js +3 -3
  32. package/dist/components/core/Calendar/CalendarEvent/CalendarEvent.types.d.ts +5 -6
  33. package/dist/components/core/Card/Card.d.ts +2 -2
  34. package/dist/components/core/Card/Card.js +3 -3
  35. package/dist/components/core/Card/Card.theme.js +3 -3
  36. package/dist/components/core/Card/Card.types.d.ts +4 -4
  37. package/dist/components/core/Card/CardBody.d.ts +3 -0
  38. package/dist/components/core/Card/CardBody.js +11 -0
  39. package/dist/components/core/Card/index.d.ts +2 -2
  40. package/dist/components/core/Carousel/Carousel.js +4 -4
  41. package/dist/components/core/Carousel/Carousel.types.d.ts +4 -4
  42. package/dist/components/core/Carousel/CarouselBody.d.ts +4 -0
  43. package/dist/components/core/Carousel/{CarouselContent.js → CarouselBody.js} +3 -3
  44. package/dist/components/core/Carousel/index.d.ts +2 -1
  45. package/dist/components/core/ContextMenu/ContextMenu.d.ts +2 -2
  46. package/dist/components/core/ContextMenu/ContextMenu.js +6 -6
  47. package/dist/components/core/ContextMenu/ContextMenu.types.d.ts +2 -2
  48. package/dist/components/core/ContextMenu/ContextMenuBody.d.ts +6 -0
  49. package/dist/components/core/ContextMenu/{ContextMenuContent.js → ContextMenuBody.js} +4 -4
  50. package/dist/components/core/ContextMenu/ContextMenuSubBody.d.ts +6 -0
  51. package/dist/components/core/ContextMenu/{ContextMenuSubContent.js → ContextMenuSubBody.js} +4 -4
  52. package/dist/components/core/ContextMenu/index.d.ts +1 -1
  53. package/dist/components/core/Drawer/Drawer.d.ts +2 -2
  54. package/dist/components/core/Drawer/Drawer.js +28 -9
  55. package/dist/components/core/Drawer/Drawer.theme.js +1 -1
  56. package/dist/components/core/Drawer/Drawer.types.d.ts +8 -6
  57. package/dist/components/core/Drawer/DrawerBody.d.ts +5 -0
  58. package/dist/components/core/Drawer/DrawerBody.js +11 -0
  59. package/dist/components/core/Drawer/index.d.ts +2 -1
  60. package/dist/components/core/Dropdown/Dropdown.types.d.ts +3 -3
  61. package/dist/components/core/Dropdown/DropdownSection.js +3 -1
  62. package/dist/components/core/FileTypeIcon/FileTypeIcon.d.ts +3 -0
  63. package/dist/components/core/FileTypeIcon/FileTypeIcon.js +33 -0
  64. package/dist/components/core/FileTypeIcon/FileTypeIcon.theme.d.ts +2 -0
  65. package/dist/components/core/FileTypeIcon/FileTypeIcon.theme.js +12 -0
  66. package/dist/components/core/FileTypeIcon/FileTypeIcon.types.d.ts +19 -0
  67. package/dist/components/core/FileTypeIcon/fileTypes.d.ts +7 -0
  68. package/dist/components/core/FileTypeIcon/fileTypes.js +30 -0
  69. package/dist/components/core/FileTypeIcon/index.d.ts +2 -0
  70. package/dist/components/core/MenuItem/MenuItem.js +3 -1
  71. package/dist/components/core/MenuItem/MenuItem.theme.js +1 -1
  72. package/dist/components/core/MenuItem/MenuItem.types.d.ts +1 -1
  73. package/dist/components/core/Message/Message.d.ts +1 -1
  74. package/dist/components/core/Message/Message.js +3 -3
  75. package/dist/components/core/Message/Message.theme.js +2 -2
  76. package/dist/components/core/Message/Message.types.d.ts +7 -7
  77. package/dist/components/core/Message/MessageAvatar.d.ts +2 -2
  78. package/dist/components/core/Message/MessageAvatar.js +3 -3
  79. package/dist/components/core/Message/MessageBody.d.ts +8 -0
  80. package/dist/components/core/Message/{MessageContent.js → MessageBody.js} +3 -3
  81. package/dist/components/core/Message/index.d.ts +2 -0
  82. package/dist/components/core/Modal/Modal.js +5 -1
  83. package/dist/components/core/Modal/Modal.theme.js +1 -1
  84. package/dist/components/core/Modal/Modal.types.d.ts +5 -2
  85. package/dist/components/core/ModalStack/ModalStackModal.js +1 -0
  86. package/dist/components/core/PageHeading/PageHeading.types.d.ts +1 -1
  87. package/dist/components/core/PageHeading/PageHeadingBackButton.js +3 -1
  88. package/dist/components/core/Popover/Popover.d.ts +1 -1
  89. package/dist/components/core/Popover/Popover.js +4 -4
  90. package/dist/components/core/Popover/Popover.theme.d.ts +1 -1
  91. package/dist/components/core/Popover/Popover.theme.js +2 -2
  92. package/dist/components/core/Popover/Popover.types.d.ts +3 -3
  93. package/dist/components/core/Popover/PopoverBody.d.ts +7 -0
  94. package/dist/components/core/Popover/{PopoverContent.js → PopoverBody.js} +24 -13
  95. package/dist/components/core/Popover/index.d.ts +4 -3
  96. package/dist/components/core/Tabs/Tabs.animations.d.ts +2 -2
  97. package/dist/components/core/Tabs/Tabs.animations.js +3 -3
  98. package/dist/components/core/Tabs/Tabs.d.ts +1 -1
  99. package/dist/components/core/Tabs/Tabs.js +3 -3
  100. package/dist/components/core/Tabs/Tabs.theme.d.ts +1 -1
  101. package/dist/components/core/Tabs/Tabs.theme.js +2 -2
  102. package/dist/components/core/Tabs/Tabs.types.d.ts +9 -9
  103. package/dist/components/core/Tabs/TabsBody.d.ts +6 -0
  104. package/dist/components/core/Tabs/{TabsContent.js → TabsBody.js} +8 -8
  105. package/dist/components/core/Tabs/index.d.ts +2 -2
  106. package/dist/components/core/Tag/Tag.d.ts +1 -1
  107. package/dist/components/core/Tag/Tag.js +2 -2
  108. package/dist/components/core/Tag/Tag.types.d.ts +1 -1
  109. package/dist/components/core/Toast/Toast.js +5 -1
  110. package/dist/components/core/Toast/Toast.types.d.ts +9 -9
  111. package/dist/components/core/index.d.ts +1 -1
  112. package/dist/components/core/index.js +7 -3
  113. package/dist/components/data-display/Feed/Feed.animations.d.ts +40 -0
  114. package/dist/components/data-display/Feed/Feed.animations.js +26 -0
  115. package/dist/components/data-display/Feed/Feed.d.ts +5 -1
  116. package/dist/components/data-display/Feed/Feed.js +87 -52
  117. package/dist/components/data-display/Feed/Feed.theme.js +11 -13
  118. package/dist/components/data-display/Feed/Feed.types.d.ts +35 -34
  119. package/dist/components/data-display/Feed/index.d.ts +1 -1
  120. package/dist/components/data-display/GanttChart/GanttTaskBar.js +11 -9
  121. package/dist/components/data-display/GanttChart/GanttTaskContextMenu.js +1 -1
  122. package/dist/components/data-display/KPI/KPI.js +2 -2
  123. package/dist/components/data-display/KPI/KPI.types.d.ts +3 -3
  124. package/dist/components/data-display/Metric/Metric.js +2 -2
  125. package/dist/components/data-display/Metric/Metric.types.d.ts +3 -3
  126. package/dist/components/data-display/Table/TableColumnManager.js +2 -1
  127. package/dist/components/data-display/Table/TableFilter.js +2 -1
  128. package/dist/components/data-display/Timeline/TimelineMarker.js +2 -2
  129. package/dist/components/effects/3d/index.d.ts +1 -1
  130. package/dist/components/effects/AIOrb/AIOrb.d.ts +1 -0
  131. package/dist/components/effects/AIOrb/AIOrb.js +3 -2
  132. package/dist/components/effects/AIOrb/AIOrb.types.d.ts +1 -0
  133. package/dist/components/effects/AIOrb/hooks/index.d.ts +2 -0
  134. package/dist/components/effects/AIOrb/hooks/useOrbState.d.ts +20 -0
  135. package/dist/components/effects/AIOrb/hooks/useOrbState.js +27 -0
  136. package/dist/components/effects/AIOrb/index.d.ts +2 -2
  137. package/dist/components/effects/AIOrb/variants/Aura/Aura.d.ts +3 -0
  138. package/dist/components/effects/AIOrb/variants/Aura/Aura.js +75 -0
  139. package/dist/components/effects/AIOrb/variants/Aura/Aura.shaders.d.ts +28 -0
  140. package/dist/components/effects/AIOrb/variants/Aura/Aura.shaders.js +191 -0
  141. package/dist/components/effects/AIOrb/variants/Aura/Aura.types.d.ts +53 -0
  142. package/dist/components/effects/AIOrb/variants/Aura/ShaderCanvas.d.ts +17 -0
  143. package/dist/components/effects/AIOrb/variants/Aura/ShaderCanvas.js +149 -0
  144. package/dist/components/effects/AIOrb/variants/Aura/index.d.ts +2 -0
  145. package/dist/components/effects/AIOrb/variants/DotSphere/DotSphere.js +38 -7
  146. package/dist/components/effects/AIOrb/variants/DotSphere/DotSphere.types.d.ts +6 -0
  147. package/dist/components/effects/AIOrb/variants/Liquid/Liquid.js +34 -8
  148. package/dist/components/effects/AIOrb/variants/Liquid/Liquid.types.d.ts +6 -0
  149. package/dist/components/effects/AIOrb/variants/index.d.ts +2 -0
  150. package/dist/components/effects/CustomCursor/CustomCursor.d.ts +2 -2
  151. package/dist/components/effects/CustomCursor/CustomCursor.js +50 -47
  152. package/dist/components/effects/GlassSurface/GlassSurface.js +24 -12
  153. package/dist/components/effects/GlassSurface/GlassSurface.types.d.ts +8 -0
  154. package/dist/components/forms/Checkbox/Checkbox.js +1 -1
  155. package/dist/components/forms/Checkbox/Checkbox.types.d.ts +5 -5
  156. package/dist/components/forms/Checkbox/CheckboxGroup.js +2 -2
  157. package/dist/components/forms/ColorPicker/ColorPicker.d.ts +1 -1
  158. package/dist/components/forms/ColorPicker/ColorPicker.js +2 -2
  159. package/dist/components/forms/ColorPicker/ColorPicker.types.d.ts +2 -2
  160. package/dist/components/forms/ColorPicker/ColorPickerBody.d.ts +7 -0
  161. package/dist/components/forms/ColorPicker/{ColorPickerContent.js → ColorPickerBody.js} +5 -5
  162. package/dist/components/forms/ColorPicker/index.d.ts +2 -2
  163. package/dist/components/forms/DatePicker/DatePicker.d.ts +7 -3
  164. package/dist/components/forms/DatePicker/DatePicker.js +6 -5
  165. package/dist/components/forms/DatePicker/DatePicker.theme.js +3 -3
  166. package/dist/components/forms/DatePicker/DatePicker.types.d.ts +9 -4
  167. package/dist/components/forms/DatePicker/DatePickerBody.d.ts +7 -0
  168. package/dist/components/forms/DatePicker/{DatePickerContent.js → DatePickerBody.js} +10 -9
  169. package/dist/components/forms/DatePicker/index.d.ts +2 -2
  170. package/dist/components/forms/FileUpload/FileUpload.js +0 -78
  171. package/dist/components/forms/Input/Input.js +2 -2
  172. package/dist/components/forms/Input/Input.types.d.ts +4 -4
  173. package/dist/components/forms/Mention/Mention.js +2 -2
  174. package/dist/components/forms/Radio/Radio.js +1 -1
  175. package/dist/components/forms/Radio/Radio.types.d.ts +5 -5
  176. package/dist/components/forms/Radio/RadioGroup.js +1 -1
  177. package/dist/components/forms/Select/Select.js +2 -2
  178. package/dist/components/forms/Select/Select.types.d.ts +4 -4
  179. package/dist/components/forms/Switch/Switch.js +1 -1
  180. package/dist/components/forms/Switch/Switch.types.d.ts +4 -4
  181. package/dist/components/forms/Textarea/Textarea.js +2 -2
  182. package/dist/components/forms/Textarea/Textarea.types.d.ts +4 -4
  183. package/dist/components/forms/TimePicker/TimePickerContent.js +1 -78
  184. package/dist/components/forms/index.d.ts +2 -2
  185. package/dist/components/forms/index.js +2 -80
  186. package/dist/components/layout/FormLayout/FormLayout.d.ts +0 -2
  187. package/dist/components/layout/FormLayout/FormLayout.js +12 -6
  188. package/dist/components/layout/FormLayout/FormLayout.theme.js +2 -5
  189. package/dist/components/layout/FormLayout/FormLayout.types.d.ts +8 -26
  190. package/dist/components/layout/FormLayout/FormLayoutSection.js +3 -2
  191. package/dist/components/layout/FormLayout/index.d.ts +1 -1
  192. package/dist/index.js +197 -199
  193. package/dist/styles.css +1 -1
  194. package/dist/utils/index.d.ts +1 -0
  195. package/dist/utils/paletteGenerator.d.ts +46 -0
  196. package/package.json +1 -1
  197. package/src/styles/theme.css +2 -6
  198. package/dist/components/core/Accordion/AccordionContent.d.ts +0 -3
  199. package/dist/components/core/Card/CardContent.d.ts +0 -3
  200. package/dist/components/core/Card/CardContent.js +0 -11
  201. package/dist/components/core/Carousel/CarouselContent.d.ts +0 -4
  202. package/dist/components/core/ContextMenu/ContextMenuContent.d.ts +0 -6
  203. package/dist/components/core/ContextMenu/ContextMenuSubContent.d.ts +0 -6
  204. package/dist/components/core/Drawer/DrawerContent.d.ts +0 -5
  205. package/dist/components/core/Drawer/DrawerContent.js +0 -11
  206. package/dist/components/core/Loader/Loader.d.ts +0 -24
  207. package/dist/components/core/Loader/Loader.js +0 -57
  208. package/dist/components/core/Loader/Loader.theme.d.ts +0 -27
  209. package/dist/components/core/Loader/Loader.theme.js +0 -60
  210. package/dist/components/core/Loader/Loader.types.d.ts +0 -71
  211. package/dist/components/core/Loader/index.d.ts +0 -2
  212. package/dist/components/core/Message/MessageContent.d.ts +0 -8
  213. package/dist/components/core/Popover/PopoverContent.d.ts +0 -7
  214. package/dist/components/core/Tabs/TabsContent.d.ts +0 -6
  215. package/dist/components/forms/ColorPicker/ColorPickerContent.d.ts +0 -7
  216. package/dist/components/forms/DatePicker/DatePickerContent.d.ts +0 -7
  217. package/dist/components/layout/FormLayout/FormLayoutBody.d.ts +0 -3
  218. package/dist/components/layout/FormLayout/FormLayoutBody.js +0 -91
  219. package/dist/components/layout/FormLayout/FormLayoutHeader.d.ts +0 -3
  220. package/dist/components/layout/FormLayout/FormLayoutHeader.js +0 -12
@@ -38,7 +38,7 @@ export interface KPIProps extends Omit<HTMLAttributes<HTMLDivElement>, "title">
38
38
  /**
39
39
  * Label describing the metric (e.g. "Fund raised", "Total Revenue")
40
40
  */
41
- label?: string;
41
+ label?: ReactNode;
42
42
  /**
43
43
  * Percentage change value (e.g. 20, -5.3). Determines trend direction & color.
44
44
  */
@@ -46,7 +46,7 @@ export interface KPIProps extends Omit<HTMLAttributes<HTMLDivElement>, "title">
46
46
  /**
47
47
  * Custom trend label override (default: auto-formats as "+20%" or "-5.3%")
48
48
  */
49
- trendLabel?: string;
49
+ trendLabel?: ReactNode;
50
50
  /**
51
51
  * Progress value from 0-100. Controls how many bars are filled.
52
52
  */
@@ -59,7 +59,7 @@ export interface KPIProps extends Omit<HTMLAttributes<HTMLDivElement>, "title">
59
59
  /**
60
60
  * Subtitle text below the bars (e.g. "Compared to last month")
61
61
  */
62
- subtitle?: string;
62
+ subtitle?: ReactNode;
63
63
  /**
64
64
  * Icon to display before the label.
65
65
  */
@@ -11,9 +11,9 @@ const Metric = React__default.forwardRef(({ value, label, subtitle, trendValue,
11
11
  const variantStyles = metricTheme.variants[variant];
12
12
  const variantColorStyles = metricTheme.variantColors[variant] || "";
13
13
  const iconStyles = ((_a = metricTheme.iconContainerVariantColors[variant]) === null || _a === void 0 ? void 0 : _a[color]) || "";
14
- return (jsx("div", { ref: ref, className: cn(metricTheme.baseStyle, variantStyles, variantColorStyles, sizeStyles.container, className), "data-size": size, ...props, children: jsxs("div", { className: "flex flex-col gap-3 ", children: [jsxs("div", { className: cn("flex items-start gap-3", sizeStyles.contentPadding), children: [icon && (jsx("div", { className: cn(metricTheme.iconContainerStyle, iconStyles, sizeStyles.iconContainer), children: icon })), jsxs("div", { className: "flex flex-col flex-1", children: [jsx("div", { className: cn(metricTheme.labelStyle, sizeStyles.label), children: label }), jsxs("div", { className: "flex items-center gap-2", children: [jsx("div", { className: cn(metricTheme.valueStyle, sizeStyles.value), children: value }), trendValue && (jsxs("div", { className: cn("flex items-center w-fit gap-1 text-base font-medium", trendDirection === "up"
14
+ return (jsx("div", { ref: ref, className: cn(metricTheme.baseStyle, variantStyles, variantColorStyles, sizeStyles.container, className), "data-size": size, ...props, children: jsxs("div", { className: "flex flex-col gap-3 ", children: [jsxs("div", { className: cn("flex items-start gap-3", sizeStyles.contentPadding), children: [icon && (jsx("div", { className: cn(metricTheme.iconContainerStyle, iconStyles, sizeStyles.iconContainer), children: icon })), jsxs("div", { className: "flex flex-col flex-1", children: [typeof label === 'string' ? (jsx("div", { className: cn(metricTheme.labelStyle, sizeStyles.label), children: label })) : label, jsxs("div", { className: "flex items-center gap-2", children: [jsx("div", { className: cn(metricTheme.valueStyle, sizeStyles.value), children: value }), trendValue && (typeof trendValue === 'string' ? (jsxs("div", { className: cn("flex items-center w-fit gap-1 text-base font-medium", trendDirection === "up"
15
15
  ? "text-[var(--color-success)]"
16
- : "text-[var(--color-danger)]"), children: [trendIcon, " ", trendValue] }))] }), subtitle && (jsx("div", { className: cn(metricTheme.subtitleStyle, sizeStyles.subtitle), children: subtitle }))] })] }), trendChart && (jsx("div", { className: "w-full h-12 flex-shrink-0 -mt-4", children: trendChart }))] }) }));
16
+ : "text-[var(--color-danger)]"), children: [trendIcon, " ", trendValue] })) : trendValue)] }), subtitle && (typeof subtitle === 'string' ? (jsx("div", { className: cn(metricTheme.subtitleStyle, sizeStyles.subtitle), children: subtitle })) : subtitle)] })] }), trendChart && (jsx("div", { className: "w-full h-12 flex-shrink-0 -mt-4", children: trendChart }))] }) }));
17
17
  });
18
18
  Metric.displayName = "Metric";
19
19
 
@@ -12,16 +12,16 @@ export interface MetricProps extends React.HTMLAttributes<HTMLDivElement> {
12
12
  /**
13
13
  * Label describing the metric
14
14
  */
15
- label: string;
15
+ label: React.ReactNode;
16
16
  /**
17
17
  * Optional subtitle or secondary text
18
18
  */
19
- subtitle?: string;
19
+ subtitle?: React.ReactNode;
20
20
  /**
21
21
  * Trend value to display (e.g., "+10.34%", "-5.2%")
22
22
  * Also acts as boolean - if provided, trend badge is shown
23
23
  */
24
- trendValue?: string;
24
+ trendValue?: React.ReactNode;
25
25
  /**
26
26
  * Trend direction - determines icon and color
27
27
  * @default 'up'
@@ -1,6 +1,7 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { Popover } from '../../core/Popover/Popover.js';
3
3
  import '../../core/Popover/PopoverContext.js';
4
+ import '../../core/Popover/PopoverBody.js';
4
5
  import { Cog6ToothIcon } from '@heroicons/react/24/outline';
5
6
  import { Button } from '../../core/Button/Button.js';
6
7
  import 'react';
@@ -17,7 +18,7 @@ function TableColumnManagerComponent({ columns, visibleColumns, columnOrder, onT
17
18
  const displayName = typeof column.header === 'string' ? column.header : column.id;
18
19
  return (jsx(Checkbox, { id: `column-checkbox-${column.id}`, name: `column-${column.id}`, value: column.id, checked: isVisible, onChange: () => onToggleColumn(column.id), "aria-label": `Toggle visibility for ${displayName} column`, label: displayName, state: isLocked ? 'disabled' : 'default' }));
19
20
  };
20
- return (jsxs(Popover, { placement: "bottom-end", offset: 8, children: [jsx(Popover.Trigger, { children: jsxs(Button, { color: "neutral", variant: "filled", "aria-label": "Manage column visibility", children: [jsx(Cog6ToothIcon, { className: "size-5", "aria-hidden": "true" }), "Manage Columns"] }) }), jsx(Popover.Content, { className: "p-0", children: jsxs("div", { className: "w-64 p-3 overflow-hidden", role: "dialog", "aria-labelledby": "column-manager-title", "aria-describedby": "column-manager-description", "aria-modal": "true", children: [jsx("div", { id: "column-manager-title", className: "text-sm uppercase font-bold mb-3 text-[var(--color-text-placeholder)]", children: "Manage Columns" }), jsx("div", { id: "column-manager-description", className: "sr-only", children: "Use checkboxes to control which columns are visible in the table. Locked columns cannot be hidden." }), jsx("div", { className: "space-y-0.5", role: "group", "aria-label": "Column visibility options", children: onColumnReorder ? (jsx(Sortable, { onReorder: onColumnReorder, showDragHandle: true, className: "space-y-0.5", children: orderedColumns.map((column) => (jsx(SortableItem, { id: column.id, disabled: column.locked === true, className: `hover:bg-[var(--color-background-tertiary)] rounded-lg p-1.5 transition-colors ${column.locked ? 'bg-[var(--color-background-secondary)]' : ''}`, children: renderColumnItem(column) }, column.id))) })) : (orderedColumns.map((column) => (jsx("div", { className: `hover:bg-[var(--color-background-tertiary)] rounded-lg p-1.5 transition-colors ${column.locked ? 'bg-[var(--color-background-secondary)]' : ''}`, children: renderColumnItem(column) }, column.id)))) }), jsx("div", { className: "mt-3 flex justify-end", children: jsx(Button, { color: "neutral", variant: "filled", className: "w-full", onClick: onResetToDefault, children: "Reset to Default" }) })] }) })] }));
21
+ return (jsxs(Popover, { placement: "bottom-end", offset: 8, children: [jsx(Popover.Trigger, { children: jsxs(Button, { color: "neutral", variant: "filled", "aria-label": "Manage column visibility", children: [jsx(Cog6ToothIcon, { className: "size-5", "aria-hidden": "true" }), "Manage Columns"] }) }), jsx(Popover.Body, { className: "p-0", children: jsxs("div", { className: "w-64 p-3 overflow-hidden", role: "dialog", "aria-labelledby": "column-manager-title", "aria-describedby": "column-manager-description", "aria-modal": "true", children: [jsx("div", { id: "column-manager-title", className: "text-sm uppercase font-bold mb-3 text-[var(--color-text-placeholder)]", children: "Manage Columns" }), jsx("div", { id: "column-manager-description", className: "sr-only", children: "Use checkboxes to control which columns are visible in the table. Locked columns cannot be hidden." }), jsx("div", { className: "space-y-0.5", role: "group", "aria-label": "Column visibility options", children: onColumnReorder ? (jsx(Sortable, { onReorder: onColumnReorder, showDragHandle: true, className: "space-y-0.5", children: orderedColumns.map((column) => (jsx(SortableItem, { id: column.id, disabled: column.locked === true, className: `hover:bg-[var(--color-background-tertiary)] rounded-lg p-1.5 transition-colors ${column.locked ? 'bg-[var(--color-background-secondary)]' : ''}`, children: renderColumnItem(column) }, column.id))) })) : (orderedColumns.map((column) => (jsx("div", { className: `hover:bg-[var(--color-background-tertiary)] rounded-lg p-1.5 transition-colors ${column.locked ? 'bg-[var(--color-background-secondary)]' : ''}`, children: renderColumnItem(column) }, column.id)))) }), jsx("div", { className: "mt-3 flex justify-end", children: jsx(Button, { color: "neutral", variant: "filled", className: "w-full", onClick: onResetToDefault, children: "Reset to Default" }) })] }) })] }));
21
22
  }
22
23
  const TableColumnManager = TableColumnManagerComponent;
23
24
 
@@ -8,6 +8,7 @@ import { Select } from '../../forms/Select/Select.js';
8
8
  import '../../forms/Select/Select.theme.js';
9
9
  import { Popover } from '../../core/Popover/Popover.js';
10
10
  import '../../core/Popover/PopoverContext.js';
11
+ import '../../core/Popover/PopoverBody.js';
11
12
  import { FunnelIcon, XMarkIcon, PlusIcon } from '@heroicons/react/24/outline';
12
13
  import { cn } from '../../../utils/cn.js';
13
14
 
@@ -206,7 +207,7 @@ function TableFilter({ columns, filterConfig, onFilterChange, filterLogic: contr
206
207
  return true;
207
208
  return f.value != null && f.value !== "";
208
209
  }).length;
209
- return (jsxs(Popover, { placement: "bottom-end", offset: 8, closeOnClickOutside: false, children: [jsx(Popover.Trigger, { children: jsxs(Button, { color: "neutral", variant: "outline", "aria-label": "Filter table data", size: "sm", children: [jsx(FunnelIcon, { className: "size-4", "aria-hidden": "true" }), "Filters", appliedFilterCount > 0 && (jsx("span", { className: "ml-1 inline-flex items-center justify-center size-5 rounded-full bg-[var(--color-primary)] text-[var(--color-primary-contrast)] text-sm font-medium", children: appliedFilterCount }))] }) }), jsx(Popover.Content, { className: "p-0 max-w-none", children: jsxs("div", { className: cn("w-[500px] p-3", className), role: "dialog", "aria-labelledby": "table-filter-title", "aria-modal": "true", children: [jsxs("div", { className: "flex items-center justify-between mb-3", children: [jsx("div", { id: "table-filter-title", className: "text-sm uppercase font-bold text-[var(--color-text-placeholder)]", children: "Filters" }), activeFilters.length > 1 && (jsxs("div", { className: "flex items-center gap-0.5 rounded-md bg-[var(--color-background-secondary)] p-0.5", children: [jsx("button", { type: "button", className: cn("px-2.5 py-0.5 text-sm font-medium rounded transition-colors", filterLogic === "and"
210
+ return (jsxs(Popover, { placement: "bottom-end", offset: 8, closeOnClickOutside: false, children: [jsx(Popover.Trigger, { children: jsxs(Button, { color: "neutral", variant: "outline", "aria-label": "Filter table data", size: "sm", children: [jsx(FunnelIcon, { className: "size-4", "aria-hidden": "true" }), "Filters", appliedFilterCount > 0 && (jsx("span", { className: "ml-1 inline-flex items-center justify-center size-5 rounded-full bg-[var(--color-primary)] text-[var(--color-primary-contrast)] text-sm font-medium", children: appliedFilterCount }))] }) }), jsx(Popover.Body, { className: "p-0 max-w-none", children: jsxs("div", { className: cn("w-[500px] p-3", className), role: "dialog", "aria-labelledby": "table-filter-title", "aria-modal": "true", children: [jsxs("div", { className: "flex items-center justify-between mb-3", children: [jsx("div", { id: "table-filter-title", className: "text-sm uppercase font-bold text-[var(--color-text-placeholder)]", children: "Filters" }), activeFilters.length > 1 && (jsxs("div", { className: "flex items-center gap-0.5 rounded-md bg-[var(--color-background-secondary)] p-0.5", children: [jsx("button", { type: "button", className: cn("px-2.5 py-0.5 text-sm font-medium rounded transition-colors", filterLogic === "and"
210
211
  ? "bg-[var(--color-background)] text-[var(--color-text-primary)] shadow-sm"
211
212
  : "text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"), onClick: () => handleSetLogic("and"), children: "AND" }), jsx("button", { type: "button", className: cn("px-2.5 py-0.5 text-sm font-medium rounded transition-colors", filterLogic === "or"
212
213
  ? "bg-[var(--color-background)] text-[var(--color-text-primary)] shadow-sm"
@@ -28,9 +28,9 @@ const TimelineMarker = React__default.forwardRef(({ icon, className, ...props },
28
28
  const variants = shouldReduceMotion ? undefined : timelineMarkerVariants;
29
29
  // Filter out conflicting motion props
30
30
  const { onDrag, onDragEnd, onDragStart, onAnimationStart, onAnimationEnd, ...safeProps } = props;
31
- return (jsxs("div", { className: cn("relative flex flex-col items-center", isHorizontal && "flex-row"), children: [jsx(motion.div, { ref: ref, className: cn(theme.markerStyle, theme.markerStatuses[status], className), "data-status": status, "aria-label": `${status} step`, initial: variants ? "hidden" : undefined, animate: variants ? "visible" : undefined, variants: variants, ...safeProps, children: renderIcon() }), !isLast && !isHorizontal && (jsx("div", { className: cn("w-0.5 flex-1 min-h-4", status === "completed"
31
+ return (jsxs("div", { className: cn("relative flex flex-col items-center", isHorizontal && "w-full"), children: [jsx(motion.div, { ref: ref, className: cn(theme.markerStyle, theme.markerStatuses[status], className), "data-status": status, "aria-label": `${status} step`, initial: variants ? "hidden" : undefined, animate: variants ? "visible" : undefined, variants: variants, ...safeProps, children: renderIcon() }), !isLast && !isHorizontal && (jsx("div", { className: cn("w-0.5 flex-1 min-h-4", status === "completed"
32
32
  ? "bg-[var(--color-success)]"
33
- : "bg-[var(--color-border)]"), "aria-hidden": "true" })), !isLast && isHorizontal && (jsx("div", { className: cn("h-0.5 flex-1 min-w-4", status === "completed"
33
+ : "bg-[var(--color-border)]"), "aria-hidden": "true" })), !isLast && isHorizontal && (jsx("div", { className: cn("absolute top-1/2 -translate-y-1/2 left-1/2 h-0.5 w-full", status === "completed"
34
34
  ? "bg-[var(--color-success)]"
35
35
  : "bg-[var(--color-border)]"), "aria-hidden": "true" }))] }));
36
36
  });
@@ -1,5 +1,5 @@
1
1
  export { AIOrb } from "../AIOrb";
2
- export type { AIOrbProps, DotSphereProps, LiquidProps } from "../AIOrb";
2
+ export type { AIOrbProps, OrbState, DotSphereProps, LiquidProps, AuraProps } from "../AIOrb";
3
3
  export { Particles } from "../Particles";
4
4
  export type { ParticlesProps } from "../Particles";
5
5
  export { SpotlightBorder } from "../SpotlightBorder";
@@ -3,4 +3,5 @@ import type { AIOrbProps } from "./AIOrb.types";
3
3
  export declare const AIOrb: React.FC<AIOrbProps> & {
4
4
  DotSphere: React.FC<import("./variants").DotSphereProps>;
5
5
  Liquid: React.FC<import("./variants").LiquidProps>;
6
+ Aura: React.FC<import("./variants").AuraProps>;
6
7
  };
@@ -2,6 +2,7 @@ import { jsx } from 'react/jsx-runtime';
2
2
  import { cn } from '../../../utils/cn.js';
3
3
  import { DotSphere } from './variants/DotSphere/DotSphere.js';
4
4
  import { Liquid } from './variants/Liquid/Liquid.js';
5
+ import { Aura } from './variants/Aura/Aura.js';
5
6
 
6
7
  const AIOrbRoot = ({ size, backgroundColor = "#000", className, style, children, ...props }) => {
7
8
  const containerStyle = {
@@ -9,8 +10,8 @@ const AIOrbRoot = ({ size, backgroundColor = "#000", className, style, children,
9
10
  ...(size ? { width: size, height: size } : {}),
10
11
  ...style,
11
12
  };
12
- return (jsx("div", { className: cn("relative overflow-hidden", !size && "w-full h-full", className), style: containerStyle, ...props, children: children }));
13
+ return (jsx("div", { className: cn("relative overflow-visible", !size && "w-full h-full", className), style: containerStyle, ...props, children: children }));
13
14
  };
14
- const AIOrb = Object.assign(AIOrbRoot, { DotSphere, Liquid });
15
+ const AIOrb = Object.assign(AIOrbRoot, { DotSphere, Liquid, Aura });
15
16
 
16
17
  export { AIOrb };
@@ -1,4 +1,5 @@
1
1
  import React from "react";
2
+ export type OrbState = "idle" | "listening" | "thinking" | "speaking";
2
3
  export interface AIOrbProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "color"> {
3
4
  /**
4
5
  * Fixed size in pixels. If omitted the orb fills its parent.
@@ -0,0 +1,2 @@
1
+ export { useOrbState } from "./useOrbState";
2
+ export type { StateParamConfig } from "./useOrbState";
@@ -0,0 +1,20 @@
1
+ import type { OrbState } from "../AIOrb.types";
2
+ /**
3
+ * State-to-parameter configuration. Maps each OrbState to a set of numeric
4
+ * target values that will be smoothly interpolated.
5
+ */
6
+ export type StateParamConfig<T extends Record<string, number>> = Record<OrbState, T>;
7
+ /**
8
+ * Generic ref-based interpolation hook for orb state-driven animation.
9
+ *
10
+ * - When `state` is defined, target values come from the config map.
11
+ * - When `state` is undefined, target values come from the `propValues` fallback
12
+ * (backwards-compatible — orb behaves exactly as if no state was set).
13
+ * - Returns a mutable `valuesRef` read inside animation loops, and a `tick(dt)`
14
+ * function that advances the interpolation by `dt` seconds.
15
+ * - Zero React re-renders — all mutation is ref-based.
16
+ */
17
+ export declare function useOrbState<T extends Record<string, number>>(state: OrbState | undefined, config: StateParamConfig<T>, propValues: T, damping?: number): {
18
+ readonly valuesRef: import("react").RefObject<T>;
19
+ readonly tick: (dt: number) => void;
20
+ };
@@ -0,0 +1,27 @@
1
+ import { useRef, useCallback } from 'react';
2
+
3
+ /**
4
+ * Generic ref-based interpolation hook for orb state-driven animation.
5
+ *
6
+ * - When `state` is defined, target values come from the config map.
7
+ * - When `state` is undefined, target values come from the `propValues` fallback
8
+ * (backwards-compatible — orb behaves exactly as if no state was set).
9
+ * - Returns a mutable `valuesRef` read inside animation loops, and a `tick(dt)`
10
+ * function that advances the interpolation by `dt` seconds.
11
+ * - Zero React re-renders — all mutation is ref-based.
12
+ */
13
+ function useOrbState(state, config, propValues, damping = 4) {
14
+ const valuesRef = useRef({ ...propValues });
15
+ const tick = useCallback((dt) => {
16
+ const target = state ? config[state] : propValues;
17
+ const current = valuesRef.current;
18
+ const factor = 1 - Math.exp(-damping * dt);
19
+ for (const key in target) {
20
+ current[key] = (current[key] +
21
+ (target[key] - current[key]) * factor);
22
+ }
23
+ }, [state, config, propValues, damping]);
24
+ return { valuesRef, tick };
25
+ }
26
+
27
+ export { useOrbState };
@@ -1,3 +1,3 @@
1
1
  export { AIOrb } from "./AIOrb";
2
- export type { AIOrbProps } from "./AIOrb.types";
3
- export type { DotSphereProps, LiquidProps } from "./variants";
2
+ export type { AIOrbProps, OrbState } from "./AIOrb.types";
3
+ export type { DotSphereProps, LiquidProps, AuraProps } from "./variants";
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ import type { AuraProps } from "./Aura.types";
3
+ export declare const Aura: React.FC<AuraProps>;
@@ -0,0 +1,75 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useMemo } from 'react';
3
+ import { useOrbState } from '../../hooks/useOrbState.js';
4
+ import { ShaderCanvas } from './ShaderCanvas.js';
5
+ import { auraFragmentShader } from './Aura.shaders.js';
6
+
7
+ const STATE_CONFIG = {
8
+ idle: { speed: 10, amplitude: 1.2, frequency: 0.4, brightness: 1.0, scale: 0.2 },
9
+ listening: { speed: 20, amplitude: 1.0, frequency: 0.7, brightness: 1.75, scale: 0.3 },
10
+ thinking: { speed: 30, amplitude: 0.5, frequency: 1.0, brightness: 1.5, scale: 0.3 },
11
+ speaking: { speed: 70, amplitude: 0.75, frequency: 1.25, brightness: 1.5, scale: 0.3 },
12
+ };
13
+ // ── Hex → RGB helper ─────────────────────────────────────────────────────────
14
+ function hexToRgb(hex) {
15
+ const h = hex.replace("#", "");
16
+ const num = parseInt(h.length === 3 ? h.split("").map((c) => c + c).join("") : h, 16);
17
+ return [(num >> 16) / 255, ((num >> 8) & 0xff) / 255, (num & 0xff) / 255];
18
+ }
19
+ // ── Aura component ───────────────────────────────────────────────────────────
20
+ const Aura = ({ color = "#1FD5F9", colorShift = 0.3, speed = 10, amplitude = 2.0, frequency = 0.5, scale = 0.2, blur = 1.0, brightness = 1.5, themeMode = "dark", state, }) => {
21
+ const rgb = useMemo(() => hexToRgb(color), [color]);
22
+ const propValues = useMemo(() => ({ speed, amplitude, frequency, brightness, scale }), [speed, amplitude, frequency, brightness, scale]);
23
+ const { valuesRef, tick } = useOrbState(state, STATE_CONFIG, propValues);
24
+ // Stable uniform object — mutated in-place each frame via the getter ref
25
+ const uniforms = useMemo(() => ({
26
+ u_color: rgb,
27
+ u_colorShift: colorShift,
28
+ u_speed: speed,
29
+ u_amplitude: amplitude,
30
+ u_frequency: frequency,
31
+ u_scale: scale,
32
+ u_blur: blur,
33
+ u_brightness: brightness,
34
+ u_bloom: 0.4,
35
+ u_spacing: 0.5,
36
+ u_variance: 0.1,
37
+ u_smoothing: 1.0,
38
+ u_lightMode: themeMode === "light" ? 1.0 : 0.0,
39
+ }),
40
+ // eslint-disable-next-line react-hooks/exhaustive-deps
41
+ []);
42
+ // Sync non-interpolated props every render
43
+ uniforms.u_color = rgb;
44
+ uniforms.u_colorShift = colorShift;
45
+ uniforms.u_blur = blur;
46
+ uniforms.u_lightMode = themeMode === "light" ? 1.0 : 0.0;
47
+ // Custom ref whose getter ticks interpolation + writes interpolated values
48
+ // into the uniform object right before ShaderCanvas reads it each frame.
49
+ const tickingRef = useMemo(() => {
50
+ let lastT = 0;
51
+ return {
52
+ get current() {
53
+ const now = performance.now() / 1000;
54
+ if (lastT > 0) {
55
+ tick(Math.min(now - lastT, 0.1));
56
+ }
57
+ lastT = now;
58
+ const v = valuesRef.current;
59
+ uniforms.u_speed = v.speed;
60
+ uniforms.u_amplitude = v.amplitude;
61
+ uniforms.u_frequency = v.frequency;
62
+ uniforms.u_brightness = v.brightness;
63
+ uniforms.u_scale = v.scale;
64
+ return uniforms;
65
+ },
66
+ set current(_v) {
67
+ // no-op — ShaderCanvas never writes to this ref
68
+ },
69
+ };
70
+ // eslint-disable-next-line react-hooks/exhaustive-deps
71
+ }, [tick]);
72
+ return (jsx("div", { className: "absolute inset-0", children: jsx(ShaderCanvas, { fragmentShader: auraFragmentShader, uniformsRef: tickingRef }) }));
73
+ };
74
+
75
+ export { Aura };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Aura fragment shader — faithful port of LiveKit's AgentAudioVisualizerAura.
3
+ *
4
+ * Uses 36 iterations of turbulence-warped SDF evaluation to produce a
5
+ * luminous ring through accumulation. The ring shape emerges naturally
6
+ * from the turbulence + circle SDF interaction — not from drawing a
7
+ * ring directly.
8
+ *
9
+ * Uniforms (all from Aura component):
10
+ * u_color vec3 Base RGB colour (0-1)
11
+ * u_colorShift float HSV hue shift range across iterations (0-1)
12
+ * u_speed float Animation speed multiplier
13
+ * u_amplitude float Turbulence displacement strength
14
+ * u_frequency float Wave complexity (remapped to 2.0-15.0)
15
+ * u_scale float Circle SDF radius
16
+ * u_blur float Edge softness
17
+ * u_brightness float Overall brightness/opacity
18
+ * u_bloom float Glow intensity (dark mode only)
19
+ * u_spacing float Iteration spacing (remapped to 1.0-TAU)
20
+ * u_variance float Amplitude variance per turbulence layer
21
+ * u_smoothing float Dynamic blur smoothing factor
22
+ * u_lightMode float 0.0 = dark mode, 1.0 = light mode
23
+ *
24
+ * Built-in from ShaderCanvas:
25
+ * iTime float Elapsed seconds
26
+ * iResolution vec2 Viewport pixel dimensions
27
+ */
28
+ export declare const auraFragmentShader = "#version 300 es\nprecision highp float;\n\nuniform float iTime;\nuniform vec2 iResolution;\n\nuniform vec3 u_color;\nuniform float u_colorShift;\nuniform float u_speed;\nuniform float u_amplitude;\nuniform float u_frequency;\nuniform float u_scale;\nuniform float u_blur;\nuniform float u_brightness;\nuniform float u_bloom;\nuniform float u_spacing;\nuniform float u_variance;\nuniform float u_smoothing;\nuniform float u_lightMode;\n\nout vec4 fragColor;\n\n/* \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nconst float TAU = 6.283185;\n\n/* \u2500\u2500 Utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nvec2 randFibo(vec2 p) {\n p = fract(p * vec2(443.897, 441.423));\n p += dot(p, p.yx + 19.19);\n return fract((p.xx + p.yx) * p.xy);\n}\n\nvec3 Tonemap(vec3 x) {\n x *= 4.0;\n return x / (1.0 + x);\n}\n\nfloat luma(vec3 color) {\n return dot(color, vec3(0.299, 0.587, 0.114));\n}\n\nvec3 rgb2hsv(vec3 c) {\n vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n float d = q.x - min(q.w, q.y);\n float e = 1.0e-10;\n return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\n\nvec3 hsv2rgb(vec3 c) {\n vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\n\n/* \u2500\u2500 SDF \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nfloat sdCircle(vec2 st, float r) {\n return length(st) - r;\n}\n\n/* \u2500\u2500 Turbulence \u2014 4 layers of sinusoidal displacement with rotation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nvec2 turb(vec2 pos, float t, float it) {\n mat2 rotation = mat2(0.6, -0.25, 0.25, 0.9);\n mat2 layerRotation = mat2(0.6, -0.8, 0.8, 0.6);\n\n float frequency = mix(2.0, 15.0, u_frequency);\n float amplitude = u_amplitude;\n float frequencyGrowth = 1.4;\n float animTime = t * 0.1 * u_speed;\n\n const int LAYERS = 4;\n for (int i = 0; i < LAYERS; i++) {\n vec2 rotatedPos = pos * rotation;\n vec2 wave = sin(frequency * rotatedPos + float(i) * animTime + it);\n\n pos += (amplitude / frequency) * rotation[0] * wave;\n\n rotation *= layerRotation;\n amplitude *= mix(1.0, max(wave.x, wave.y), u_variance);\n frequency *= frequencyGrowth;\n }\n\n return pos;\n}\n\n/* \u2500\u2500 Main \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nconst float ITERATIONS = 36.0;\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / iResolution.xy;\n\n vec3 pp = vec3(0.0);\n vec3 bloom = vec3(0.0);\n float t = iTime * 0.5;\n vec2 pos = uv - 0.5;\n\n vec2 prevPos = turb(pos, t, 0.0 - 1.0 / ITERATIONS);\n float spacing = mix(1.0, TAU, u_spacing);\n\n for (float i = 1.0; i < ITERATIONS + 1.0; i++) {\n float iter = i / ITERATIONS;\n vec2 st = turb(pos, t, iter * spacing);\n float d = abs(sdCircle(st, u_scale));\n float pd = distance(st, prevPos);\n prevPos = st;\n float dynamicBlur = exp2(pd * 2.0 * 1.4426950408889634) - 1.0;\n float ds = smoothstep(0.0, u_blur * 0.05 + max(dynamicBlur * u_smoothing, 0.001), d);\n\n vec3 col = u_color;\n if (u_colorShift > 0.01) {\n vec3 hsv = rgb2hsv(col);\n hsv.x = fract(hsv.x + (1.0 - iter) * u_colorShift * 0.3);\n col = hsv2rgb(hsv);\n }\n\n float invd = 1.0 / max(d + dynamicBlur, 0.001);\n pp += (ds - 1.0) * col;\n bloom += clamp(invd, 0.0, 250.0) * col;\n }\n\n pp *= 1.0 / ITERATIONS;\n\n vec3 color;\n\n // Dark mode (default)\n if (u_lightMode < 0.5) {\n bloom = bloom / (bloom + 2e4);\n color = (-pp + bloom * 3.0 * u_bloom) * 1.2;\n color += (randFibo(gl_FragCoord.xy).x - 0.5) / 255.0;\n color = Tonemap(color);\n float alpha = luma(color) * u_brightness;\n fragColor = vec4(color * u_brightness, alpha);\n }\n // Light mode\n else {\n color = -pp;\n color += (randFibo(gl_FragCoord.xy).x - 0.5) / 255.0;\n\n float brightness = length(color);\n vec3 direction = brightness > 0.0 ? color / brightness : color;\n\n float factor = 2.0;\n float mappedBrightness = (brightness * factor) / (1.0 + brightness * factor);\n color = direction * mappedBrightness;\n\n float gray = dot(color, vec3(0.2, 0.5, 0.1));\n float saturationBoost = 3.0;\n color = mix(vec3(gray), color, saturationBoost);\n\n color = clamp(color, 0.0, 1.0);\n\n float alpha = mappedBrightness * clamp(u_brightness, 1.0, 2.0);\n fragColor = vec4(color, alpha);\n }\n}\n";
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Aura fragment shader — faithful port of LiveKit's AgentAudioVisualizerAura.
3
+ *
4
+ * Uses 36 iterations of turbulence-warped SDF evaluation to produce a
5
+ * luminous ring through accumulation. The ring shape emerges naturally
6
+ * from the turbulence + circle SDF interaction — not from drawing a
7
+ * ring directly.
8
+ *
9
+ * Uniforms (all from Aura component):
10
+ * u_color vec3 Base RGB colour (0-1)
11
+ * u_colorShift float HSV hue shift range across iterations (0-1)
12
+ * u_speed float Animation speed multiplier
13
+ * u_amplitude float Turbulence displacement strength
14
+ * u_frequency float Wave complexity (remapped to 2.0-15.0)
15
+ * u_scale float Circle SDF radius
16
+ * u_blur float Edge softness
17
+ * u_brightness float Overall brightness/opacity
18
+ * u_bloom float Glow intensity (dark mode only)
19
+ * u_spacing float Iteration spacing (remapped to 1.0-TAU)
20
+ * u_variance float Amplitude variance per turbulence layer
21
+ * u_smoothing float Dynamic blur smoothing factor
22
+ * u_lightMode float 0.0 = dark mode, 1.0 = light mode
23
+ *
24
+ * Built-in from ShaderCanvas:
25
+ * iTime float Elapsed seconds
26
+ * iResolution vec2 Viewport pixel dimensions
27
+ */
28
+ const auraFragmentShader = `#version 300 es
29
+ precision highp float;
30
+
31
+ uniform float iTime;
32
+ uniform vec2 iResolution;
33
+
34
+ uniform vec3 u_color;
35
+ uniform float u_colorShift;
36
+ uniform float u_speed;
37
+ uniform float u_amplitude;
38
+ uniform float u_frequency;
39
+ uniform float u_scale;
40
+ uniform float u_blur;
41
+ uniform float u_brightness;
42
+ uniform float u_bloom;
43
+ uniform float u_spacing;
44
+ uniform float u_variance;
45
+ uniform float u_smoothing;
46
+ uniform float u_lightMode;
47
+
48
+ out vec4 fragColor;
49
+
50
+ /* ── Constants ─────────────────────────────────────────────────────────────── */
51
+
52
+ const float TAU = 6.283185;
53
+
54
+ /* ── Utilities ─────────────────────────────────────────────────────────────── */
55
+
56
+ vec2 randFibo(vec2 p) {
57
+ p = fract(p * vec2(443.897, 441.423));
58
+ p += dot(p, p.yx + 19.19);
59
+ return fract((p.xx + p.yx) * p.xy);
60
+ }
61
+
62
+ vec3 Tonemap(vec3 x) {
63
+ x *= 4.0;
64
+ return x / (1.0 + x);
65
+ }
66
+
67
+ float luma(vec3 color) {
68
+ return dot(color, vec3(0.299, 0.587, 0.114));
69
+ }
70
+
71
+ vec3 rgb2hsv(vec3 c) {
72
+ vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
73
+ vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
74
+ vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
75
+ float d = q.x - min(q.w, q.y);
76
+ float e = 1.0e-10;
77
+ return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
78
+ }
79
+
80
+ vec3 hsv2rgb(vec3 c) {
81
+ vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
82
+ vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
83
+ return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
84
+ }
85
+
86
+ /* ── SDF ───────────────────────────────────────────────────────────────────── */
87
+
88
+ float sdCircle(vec2 st, float r) {
89
+ return length(st) - r;
90
+ }
91
+
92
+ /* ── Turbulence — 4 layers of sinusoidal displacement with rotation ────────── */
93
+
94
+ vec2 turb(vec2 pos, float t, float it) {
95
+ mat2 rotation = mat2(0.6, -0.25, 0.25, 0.9);
96
+ mat2 layerRotation = mat2(0.6, -0.8, 0.8, 0.6);
97
+
98
+ float frequency = mix(2.0, 15.0, u_frequency);
99
+ float amplitude = u_amplitude;
100
+ float frequencyGrowth = 1.4;
101
+ float animTime = t * 0.1 * u_speed;
102
+
103
+ const int LAYERS = 4;
104
+ for (int i = 0; i < LAYERS; i++) {
105
+ vec2 rotatedPos = pos * rotation;
106
+ vec2 wave = sin(frequency * rotatedPos + float(i) * animTime + it);
107
+
108
+ pos += (amplitude / frequency) * rotation[0] * wave;
109
+
110
+ rotation *= layerRotation;
111
+ amplitude *= mix(1.0, max(wave.x, wave.y), u_variance);
112
+ frequency *= frequencyGrowth;
113
+ }
114
+
115
+ return pos;
116
+ }
117
+
118
+ /* ── Main ──────────────────────────────────────────────────────────────────── */
119
+
120
+ const float ITERATIONS = 36.0;
121
+
122
+ void main() {
123
+ vec2 uv = gl_FragCoord.xy / iResolution.xy;
124
+
125
+ vec3 pp = vec3(0.0);
126
+ vec3 bloom = vec3(0.0);
127
+ float t = iTime * 0.5;
128
+ vec2 pos = uv - 0.5;
129
+
130
+ vec2 prevPos = turb(pos, t, 0.0 - 1.0 / ITERATIONS);
131
+ float spacing = mix(1.0, TAU, u_spacing);
132
+
133
+ for (float i = 1.0; i < ITERATIONS + 1.0; i++) {
134
+ float iter = i / ITERATIONS;
135
+ vec2 st = turb(pos, t, iter * spacing);
136
+ float d = abs(sdCircle(st, u_scale));
137
+ float pd = distance(st, prevPos);
138
+ prevPos = st;
139
+ float dynamicBlur = exp2(pd * 2.0 * 1.4426950408889634) - 1.0;
140
+ float ds = smoothstep(0.0, u_blur * 0.05 + max(dynamicBlur * u_smoothing, 0.001), d);
141
+
142
+ vec3 col = u_color;
143
+ if (u_colorShift > 0.01) {
144
+ vec3 hsv = rgb2hsv(col);
145
+ hsv.x = fract(hsv.x + (1.0 - iter) * u_colorShift * 0.3);
146
+ col = hsv2rgb(hsv);
147
+ }
148
+
149
+ float invd = 1.0 / max(d + dynamicBlur, 0.001);
150
+ pp += (ds - 1.0) * col;
151
+ bloom += clamp(invd, 0.0, 250.0) * col;
152
+ }
153
+
154
+ pp *= 1.0 / ITERATIONS;
155
+
156
+ vec3 color;
157
+
158
+ // Dark mode (default)
159
+ if (u_lightMode < 0.5) {
160
+ bloom = bloom / (bloom + 2e4);
161
+ color = (-pp + bloom * 3.0 * u_bloom) * 1.2;
162
+ color += (randFibo(gl_FragCoord.xy).x - 0.5) / 255.0;
163
+ color = Tonemap(color);
164
+ float alpha = luma(color) * u_brightness;
165
+ fragColor = vec4(color * u_brightness, alpha);
166
+ }
167
+ // Light mode
168
+ else {
169
+ color = -pp;
170
+ color += (randFibo(gl_FragCoord.xy).x - 0.5) / 255.0;
171
+
172
+ float brightness = length(color);
173
+ vec3 direction = brightness > 0.0 ? color / brightness : color;
174
+
175
+ float factor = 2.0;
176
+ float mappedBrightness = (brightness * factor) / (1.0 + brightness * factor);
177
+ color = direction * mappedBrightness;
178
+
179
+ float gray = dot(color, vec3(0.2, 0.5, 0.1));
180
+ float saturationBoost = 3.0;
181
+ color = mix(vec3(gray), color, saturationBoost);
182
+
183
+ color = clamp(color, 0.0, 1.0);
184
+
185
+ float alpha = mappedBrightness * clamp(u_brightness, 1.0, 2.0);
186
+ fragColor = vec4(color, alpha);
187
+ }
188
+ }
189
+ `;
190
+
191
+ export { auraFragmentShader };
@@ -0,0 +1,53 @@
1
+ import type { OrbState } from "../../AIOrb.types";
2
+ export interface AuraProps {
3
+ /**
4
+ * Base colour as a hex string.
5
+ * @default '#1FD5F9'
6
+ */
7
+ color?: string;
8
+ /**
9
+ * HSV hue shift for iridescence (0-1).
10
+ * @default 0.3
11
+ */
12
+ colorShift?: number;
13
+ /**
14
+ * Animation speed multiplier.
15
+ * @default 10
16
+ */
17
+ speed?: number;
18
+ /**
19
+ * Wave displacement strength.
20
+ * @default 2.0
21
+ */
22
+ amplitude?: number;
23
+ /**
24
+ * Wave complexity.
25
+ * @default 0.5
26
+ */
27
+ frequency?: number;
28
+ /**
29
+ * Circle SDF radius in normalized coordinates.
30
+ * @default 0.2
31
+ */
32
+ scale?: number;
33
+ /**
34
+ * Edge softness.
35
+ * @default 1.0
36
+ */
37
+ blur?: number;
38
+ /**
39
+ * Overall brightness/opacity.
40
+ * @default 1.5
41
+ */
42
+ brightness?: number;
43
+ /**
44
+ * Rendering mode — affects colour inversion for light backgrounds.
45
+ * @default 'dark'
46
+ */
47
+ themeMode?: "dark" | "light";
48
+ /**
49
+ * State-driven animation. When set, overrides speed/amplitude/frequency/
50
+ * brightness/scale with smooth interpolation towards state targets.
51
+ */
52
+ state?: OrbState;
53
+ }
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+ export interface ShaderCanvasProps {
3
+ fragmentShader: string;
4
+ uniformsRef: React.MutableRefObject<Record<string, number | number[]>>;
5
+ maxDpr?: number;
6
+ className?: string;
7
+ style?: React.CSSProperties;
8
+ }
9
+ /**
10
+ * Minimal raw WebGL2 canvas renderer for fullscreen fragment shaders.
11
+ * - Built-in uniforms: iTime (float), iResolution (vec2)
12
+ * - Custom uniforms read from `uniformsRef` each frame (no stale closures)
13
+ * - ResizeObserver for responsive canvas sizing
14
+ * - rAF animation loop with cleanup on unmount
15
+ * - Graceful degradation: renders nothing if WebGL2 unavailable
16
+ */
17
+ export declare const ShaderCanvas: React.FC<ShaderCanvasProps>;