@octaviaflow/core 3.1.0-beta.114 → 3.1.0-beta.115

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 (249) hide show
  1. package/dist/chunk-75JAQ4ZG.js +2694 -0
  2. package/dist/chunk-75JAQ4ZG.js.map +1 -0
  3. package/dist/chunk-LQVPNIO5.js +6789 -0
  4. package/dist/chunk-LQVPNIO5.js.map +1 -0
  5. package/dist/chunk-P46JGJC2.js +5619 -0
  6. package/dist/chunk-P46JGJC2.js.map +1 -0
  7. package/dist/chunk-ZALBYWCU.js +1547 -0
  8. package/dist/chunk-ZALBYWCU.js.map +1 -0
  9. package/dist/components/Accordion/Accordion.d.ts.map +1 -1
  10. package/dist/components/AgentAppMark/AgentAppMark.d.ts +28 -0
  11. package/dist/components/AgentAppMark/AgentAppMark.d.ts.map +1 -0
  12. package/dist/components/AgentAppMark/index.d.ts +3 -0
  13. package/dist/components/AgentAppMark/index.d.ts.map +1 -0
  14. package/dist/components/AgentCard/AgentCard.d.ts.map +1 -1
  15. package/dist/components/AlertCard/AlertCard.d.ts.map +1 -1
  16. package/dist/components/AuthCard/AuthCard.d.ts.map +1 -1
  17. package/dist/components/AuthScreen/AuthScreen.d.ts.map +1 -1
  18. package/dist/components/Badge/Badge.d.ts.map +1 -1
  19. package/dist/components/Banner/Banner.d.ts.map +1 -1
  20. package/dist/components/BarChart/BarChart.d.ts.map +1 -1
  21. package/dist/components/Calendar/Calendar.d.ts.map +1 -1
  22. package/dist/components/CalendarHeatmap/CalendarHeatmap.d.ts.map +1 -1
  23. package/dist/components/CalendarHeatmap/index.d.ts +1 -1
  24. package/dist/components/CalendarHeatmap/index.d.ts.map +1 -1
  25. package/dist/components/Callout/Callout.d.ts.map +1 -1
  26. package/dist/components/Card/Card.d.ts.map +1 -1
  27. package/dist/components/Catalog/Catalog.d.ts.map +1 -1
  28. package/dist/components/Catalog/index.d.ts +1 -1
  29. package/dist/components/Catalog/index.d.ts.map +1 -1
  30. package/dist/components/ChatAttachment/ChatAttachment.d.ts.map +1 -1
  31. package/dist/components/ChatAttachment/index.d.ts +1 -1
  32. package/dist/components/ChatAttachment/index.d.ts.map +1 -1
  33. package/dist/components/ChatBubble/ChatBubble.d.ts.map +1 -1
  34. package/dist/components/ChatCodeBlock/ChatCodeBlock.d.ts.map +1 -1
  35. package/dist/components/ChatDayDivider/ChatDayDivider.d.ts.map +1 -1
  36. package/dist/components/ChatFeedback/ChatFeedback.d.ts.map +1 -1
  37. package/dist/components/ChatPanel/ChatPanel.d.ts +1 -1
  38. package/dist/components/ChatPanel/ChatPanel.d.ts.map +1 -1
  39. package/dist/components/ChatScrollToBottom/ChatScrollToBottom.d.ts.map +1 -1
  40. package/dist/components/ChatSources/ChatSources.d.ts.map +1 -1
  41. package/dist/components/ChatSources/index.d.ts +1 -1
  42. package/dist/components/ChatSources/index.d.ts.map +1 -1
  43. package/dist/components/ChatSuggestions/ChatSuggestions.d.ts.map +1 -1
  44. package/dist/components/ChatSuggestions/index.d.ts +1 -1
  45. package/dist/components/ChatSuggestions/index.d.ts.map +1 -1
  46. package/dist/components/ChatThinking/ChatThinking.d.ts.map +1 -1
  47. package/dist/components/ChatThinking/index.d.ts +1 -1
  48. package/dist/components/ChatThinking/index.d.ts.map +1 -1
  49. package/dist/components/ChatThread/ChatThread.d.ts.map +1 -1
  50. package/dist/components/ChatThread/index.d.ts +1 -1
  51. package/dist/components/ChatThread/index.d.ts.map +1 -1
  52. package/dist/components/ChatToolTrace/ChatToolTrace.d.ts.map +1 -1
  53. package/dist/components/ChatToolTrace/index.d.ts +1 -1
  54. package/dist/components/ChatToolTrace/index.d.ts.map +1 -1
  55. package/dist/components/Checkbox/Checkbox.d.ts.map +1 -1
  56. package/dist/components/Chip/Chip.d.ts.map +1 -1
  57. package/dist/components/ChoiceCard/ChoiceCard.d.ts.map +1 -1
  58. package/dist/components/Coachmark/Coachmark.d.ts.map +1 -1
  59. package/dist/components/CodeEditor/CodeEditor.d.ts +15 -0
  60. package/dist/components/CodeEditor/CodeEditor.d.ts.map +1 -1
  61. package/dist/components/ColorPicker/ColorPicker.d.ts.map +1 -1
  62. package/dist/components/Combobox/Combobox.d.ts.map +1 -1
  63. package/dist/components/Combobox/index.d.ts +1 -1
  64. package/dist/components/Combobox/index.d.ts.map +1 -1
  65. package/dist/components/CommandPalette/CommandPalette.d.ts.map +1 -1
  66. package/dist/components/ConditionBuilder/ConditionBuilder.d.ts.map +1 -1
  67. package/dist/components/ConfigPanel/ConfigPanel.d.ts.map +1 -1
  68. package/dist/components/ConfirmDialog/ConfirmDialog.d.ts.map +1 -1
  69. package/dist/components/ConnectorCard/ConnectorCard.d.ts.map +1 -1
  70. package/dist/components/ConnectorCard/index.d.ts +1 -1
  71. package/dist/components/ConnectorCard/index.d.ts.map +1 -1
  72. package/dist/components/ContextMenu/ContextMenu.d.ts.map +1 -1
  73. package/dist/components/CountUp/CountUp.d.ts.map +1 -1
  74. package/dist/components/CsvViewer/CsvViewer.d.ts.map +1 -1
  75. package/dist/components/DataMapper/DataMapper.d.ts.map +1 -1
  76. package/dist/components/DataTable/DataTable.d.ts.map +1 -1
  77. package/dist/components/DatasetCard/DatasetCard.d.ts.map +1 -1
  78. package/dist/components/DatePicker/DatePicker.d.ts.map +1 -1
  79. package/dist/components/DescriptionList/DescriptionList.d.ts.map +1 -1
  80. package/dist/components/Dialog/Dialog.d.ts.map +1 -1
  81. package/dist/components/Divider/Divider.d.ts.map +1 -1
  82. package/dist/components/DonutChart/DonutChart.d.ts.map +1 -1
  83. package/dist/components/Drawer/Drawer.d.ts.map +1 -1
  84. package/dist/components/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  85. package/dist/components/EmptyState/EmptyState.d.ts.map +1 -1
  86. package/dist/components/ExecutionConsole/ExecutionConsole.d.ts.map +1 -1
  87. package/dist/components/ExpressionField/ExpressionField.d.ts +21 -3
  88. package/dist/components/ExpressionField/ExpressionField.d.ts.map +1 -1
  89. package/dist/components/ExpressionField/dataRefTokens.d.ts +52 -0
  90. package/dist/components/ExpressionField/dataRefTokens.d.ts.map +1 -0
  91. package/dist/components/ExpressionField/index.d.ts +3 -2
  92. package/dist/components/ExpressionField/index.d.ts.map +1 -1
  93. package/dist/components/FeatureCard/FeatureCard.d.ts.map +1 -1
  94. package/dist/components/FieldPicker/FieldPicker.d.ts.map +1 -1
  95. package/dist/components/FieldPicker/index.d.ts +1 -1
  96. package/dist/components/FieldPicker/index.d.ts.map +1 -1
  97. package/dist/components/FileBrowser/FileBrowser.d.ts.map +1 -1
  98. package/dist/components/FileDropzone/FileDropzone.d.ts.map +1 -1
  99. package/dist/components/FileList/FileList.d.ts.map +1 -1
  100. package/dist/components/FilePicker/FilePicker.d.ts +6 -1
  101. package/dist/components/FilePicker/FilePicker.d.ts.map +1 -1
  102. package/dist/components/FileViewer/FileViewer.d.ts.map +1 -1
  103. package/dist/components/FlowMinimap/FlowMinimap.d.ts.map +1 -1
  104. package/dist/components/Gauge/Gauge.d.ts.map +1 -1
  105. package/dist/components/Grid/Grid.d.ts.map +1 -1
  106. package/dist/components/GroupByBuilder/index.d.ts +1 -1
  107. package/dist/components/GroupByBuilder/index.d.ts.map +1 -1
  108. package/dist/components/Heatmap/Heatmap.d.ts.map +1 -1
  109. package/dist/components/IconCard/IconCard.d.ts.map +1 -1
  110. package/dist/components/InlineMessage/InlineMessage.d.ts.map +1 -1
  111. package/dist/components/IntegrationCard/IntegrationCard.d.ts.map +1 -1
  112. package/dist/components/ItemDetail/ItemDetail.d.ts.map +1 -1
  113. package/dist/components/ItemDetail/index.d.ts +1 -1
  114. package/dist/components/ItemDetail/index.d.ts.map +1 -1
  115. package/dist/components/JsonViewer/JsonViewer.d.ts.map +1 -1
  116. package/dist/components/Kbd/Kbd.d.ts.map +1 -1
  117. package/dist/components/KeyValueEditor/KeyValueEditor.d.ts +22 -1
  118. package/dist/components/KeyValueEditor/KeyValueEditor.d.ts.map +1 -1
  119. package/dist/components/KeyValueEditor/index.d.ts +1 -1
  120. package/dist/components/KeyValueEditor/index.d.ts.map +1 -1
  121. package/dist/components/LinkButton/LinkButton.d.ts.map +1 -1
  122. package/dist/components/MetricCard/MetricCard.d.ts.map +1 -1
  123. package/dist/components/MonacoEditor/MonacoDiffEditor.d.ts.map +1 -1
  124. package/dist/components/MonacoEditor/MonacoEditor.d.ts.map +1 -1
  125. package/dist/components/MultiSelect/MultiSelect.d.ts.map +1 -1
  126. package/dist/components/NumberInput/NumberInput.d.ts.map +1 -1
  127. package/dist/components/OnboardingFlow/OnboardingFlow.d.ts.map +1 -1
  128. package/dist/components/OrgSwitcher/OrgSwitcher.d.ts.map +1 -1
  129. package/dist/components/PageHeader/PageHeader.d.ts.map +1 -1
  130. package/dist/components/Pagination/Pagination.d.ts.map +1 -1
  131. package/dist/components/PasswordInput/PasswordInput.d.ts.map +1 -1
  132. package/dist/components/PhoneInput/PhoneInput.d.ts.map +1 -1
  133. package/dist/components/PhoneInput/countries.d.ts.map +1 -1
  134. package/dist/components/PhoneInput/index.d.ts +1 -1
  135. package/dist/components/PhoneInput/index.d.ts.map +1 -1
  136. package/dist/components/PipelineCard/PipelineCard.d.ts +1 -1
  137. package/dist/components/PipelineCard/PipelineCard.d.ts.map +1 -1
  138. package/dist/components/PlanCard/PlanCard.d.ts.map +1 -1
  139. package/dist/components/PlanPicker/PlanPicker.d.ts.map +1 -1
  140. package/dist/components/PlanPicker/context.d.ts.map +1 -1
  141. package/dist/components/PresenceBar/PresenceBar.d.ts +11 -0
  142. package/dist/components/PresenceBar/PresenceBar.d.ts.map +1 -1
  143. package/dist/components/PricingCard/PricingCard.d.ts.map +1 -1
  144. package/dist/components/ProductCard/ProductCard.d.ts.map +1 -1
  145. package/dist/components/ProgressBar/ProgressBar.d.ts.map +1 -1
  146. package/dist/components/ProgressRing/ProgressRing.d.ts.map +1 -1
  147. package/dist/components/PromptInput/PromptInput.d.ts.map +1 -1
  148. package/dist/components/Quote/Quote.d.ts.map +1 -1
  149. package/dist/components/Radio/Radio.d.ts.map +1 -1
  150. package/dist/components/Radio/RadioGroup.d.ts.map +1 -1
  151. package/dist/components/RangeSlider/RangeSlider.d.ts.map +1 -1
  152. package/dist/components/Rating/BinaryRating.d.ts.map +1 -1
  153. package/dist/components/Rating/Rating.d.ts.map +1 -1
  154. package/dist/components/Rating/index.d.ts +1 -1
  155. package/dist/components/Rating/index.d.ts.map +1 -1
  156. package/dist/components/Resizable/Resizable.d.ts.map +1 -1
  157. package/dist/components/Ribbon/Ribbon.d.ts.map +1 -1
  158. package/dist/components/Sankey/Sankey.d.ts.map +1 -1
  159. package/dist/components/ScheduleBuilder/ScheduleBuilder.d.ts.map +1 -1
  160. package/dist/components/ScheduleBuilder/index.d.ts +1 -1
  161. package/dist/components/ScheduleBuilder/index.d.ts.map +1 -1
  162. package/dist/components/ScrollArea/ScrollArea.d.ts.map +1 -1
  163. package/dist/components/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  164. package/dist/components/Select/Select.d.ts.map +1 -1
  165. package/dist/components/Show/Show.d.ts.map +1 -1
  166. package/dist/components/Skeleton/Skeleton.d.ts.map +1 -1
  167. package/dist/components/SlideoutPanel/SlideoutPanel.d.ts.map +1 -1
  168. package/dist/components/Slider/Slider.d.ts.map +1 -1
  169. package/dist/components/SocialButton/SocialButton.d.ts.map +1 -1
  170. package/dist/components/SortBuilder/index.d.ts +1 -1
  171. package/dist/components/SortBuilder/index.d.ts.map +1 -1
  172. package/dist/components/Sortable/Sortable.d.ts.map +1 -1
  173. package/dist/components/Sparkline/Sparkline.d.ts.map +1 -1
  174. package/dist/components/Spinner/Spinner.d.ts.map +1 -1
  175. package/dist/components/Spotlight/Spotlight.d.ts.map +1 -1
  176. package/dist/components/Stack/Stack.d.ts.map +1 -1
  177. package/dist/components/Stat/Stat.d.ts.map +1 -1
  178. package/dist/components/StatusList/StatusList.d.ts +1 -1
  179. package/dist/components/StatusList/StatusList.d.ts.map +1 -1
  180. package/dist/components/StatusList/index.d.ts +1 -1
  181. package/dist/components/StatusList/index.d.ts.map +1 -1
  182. package/dist/components/StatusTiles/StatusTiles.d.ts.map +1 -1
  183. package/dist/components/StatusTiles/index.d.ts +1 -1
  184. package/dist/components/StatusTiles/index.d.ts.map +1 -1
  185. package/dist/components/Stepper/Stepper.d.ts.map +1 -1
  186. package/dist/components/Switch/Switch.d.ts.map +1 -1
  187. package/dist/components/Table/Table.d.ts.map +1 -1
  188. package/dist/components/TagsInput/TagsInput.d.ts.map +1 -1
  189. package/dist/components/Textarea/Textarea.d.ts.map +1 -1
  190. package/dist/components/TimePicker/TimePicker.d.ts.map +1 -1
  191. package/dist/components/Timeline/Timeline.d.ts.map +1 -1
  192. package/dist/components/TimezonePicker/TimezonePicker.d.ts.map +1 -1
  193. package/dist/components/Toggle/Toggle.d.ts.map +1 -1
  194. package/dist/components/ToolCard/ToolCard.d.ts.map +1 -1
  195. package/dist/components/Tooltip/Tooltip.d.ts.map +1 -1
  196. package/dist/components/TraceStep/TraceStep.d.ts.map +1 -1
  197. package/dist/components/TreeView/TreeView.d.ts.map +1 -1
  198. package/dist/components/TreeView/index.d.ts +1 -1
  199. package/dist/components/TreeView/index.d.ts.map +1 -1
  200. package/dist/components/UsageMeter/UsageMeter.d.ts.map +1 -1
  201. package/dist/components/VersionHistory/VersionHistory.d.ts.map +1 -1
  202. package/dist/components/VersionHistory/index.d.ts +1 -1
  203. package/dist/components/VersionHistory/index.d.ts.map +1 -1
  204. package/dist/components/XmlViewer/XmlViewer.d.ts.map +1 -1
  205. package/dist/components/YamlViewer/YamlViewer.d.ts.map +1 -1
  206. package/dist/email/emailPalette.d.ts.map +1 -1
  207. package/dist/email/emailSystem.d.ts +3 -3
  208. package/dist/email/emailSystem.d.ts.map +1 -1
  209. package/dist/email/emailTemplates.d.ts +1 -1
  210. package/dist/email/emailTemplates.d.ts.map +1 -1
  211. package/dist/hooks/useRating.d.ts.map +1 -1
  212. package/dist/hooks/useTextareaCommands.d.ts.map +1 -1
  213. package/dist/hooks/useTextareaSelection.d.ts.map +1 -1
  214. package/dist/hooks/useTextareaTools.d.ts.map +1 -1
  215. package/dist/hooks/useTraceTimeline.d.ts.map +1 -1
  216. package/dist/index.cjs +15999 -17094
  217. package/dist/index.cjs.map +1 -1
  218. package/dist/index.d.ts +6 -5
  219. package/dist/index.d.ts.map +1 -1
  220. package/dist/index.js +14076 -16193
  221. package/dist/index.js.map +1 -1
  222. package/dist/marketing.cjs +580 -726
  223. package/dist/marketing.cjs.map +1 -1
  224. package/dist/marketing.js +2 -2
  225. package/dist/monaco.cjs +364 -389
  226. package/dist/monaco.cjs.map +1 -1
  227. package/dist/monaco.js +381 -410
  228. package/dist/monaco.js.map +1 -1
  229. package/dist/notifications/components/NotificationBell/NotificationBell.d.ts.map +1 -1
  230. package/dist/styles.css +1 -1
  231. package/dist/utils/Slot.d.ts.map +1 -1
  232. package/dist/utils/gradients.d.ts.map +1 -1
  233. package/dist/utils/useAnchoredPopover.d.ts +8 -1
  234. package/dist/utils/useAnchoredPopover.d.ts.map +1 -1
  235. package/dist/workflow/components/ConfigPanel/ConfigPanel.d.ts.map +1 -1
  236. package/dist/workflow/components/FlowNode/FlowNode.d.ts.map +1 -1
  237. package/dist/workflow/components/FxPanel/DataRefButton.d.ts +1 -1
  238. package/dist/workflow/components/FxPanel/DataRefButton.d.ts.map +1 -1
  239. package/dist/workflow/components/FxPanel/FxPanel.d.ts.map +1 -1
  240. package/dist/workflow/editor.d.ts +22 -0
  241. package/dist/workflow/editor.d.ts.map +1 -1
  242. package/dist/workflow/index.d.ts +6 -6
  243. package/dist/workflow/index.d.ts.map +1 -1
  244. package/dist/workflow/types.d.ts.map +1 -1
  245. package/dist/workflow.cjs +10310 -9355
  246. package/dist/workflow.cjs.map +1 -1
  247. package/dist/workflow.js +1932 -1963
  248. package/dist/workflow.js.map +1 -1
  249. package/package.json +2 -2
@@ -0,0 +1,1547 @@
1
+ import {
2
+ Slot,
3
+ resolveAccessibleName
4
+ } from "./chunk-75JAQ4ZG.js";
5
+ import {
6
+ cn
7
+ } from "./chunk-ZAUUGK2Y.js";
8
+
9
+ // src/components/Card/Card.tsx
10
+ import { motion, useReducedMotion } from "framer-motion";
11
+ import {
12
+ forwardRef
13
+ } from "react";
14
+ import { jsx } from "react/jsx-runtime";
15
+ var Card = forwardRef(function Card2({
16
+ variant = "default",
17
+ padding = "md",
18
+ radius = "md",
19
+ hoverable = false,
20
+ disabled = false,
21
+ loading = false,
22
+ asChild = false,
23
+ onClick,
24
+ onKeyDown,
25
+ className,
26
+ children,
27
+ ...rest
28
+ }, ref) {
29
+ const reducedMotion = useReducedMotion();
30
+ const isInteractive = Boolean(onClick) && !disabled && !loading;
31
+ const handleKeyDown = (e) => {
32
+ onKeyDown?.(e);
33
+ if (e.defaultPrevented) return;
34
+ if (!isInteractive) return;
35
+ if ((e.key === "Enter" || e.key === " ") && !e.repeat) {
36
+ e.preventDefault();
37
+ onClick?.(e);
38
+ }
39
+ };
40
+ const rootClassName = cn(
41
+ "ods-card",
42
+ `ods-card--${variant}`,
43
+ `ods-card--pad-${padding}`,
44
+ `ods-card--radius-${radius}`,
45
+ (hoverable || isInteractive) && !loading && !disabled && "ods-card--hoverable",
46
+ isInteractive && "ods-card--clickable",
47
+ disabled && "ods-card--disabled",
48
+ loading && "ods-card--loading",
49
+ className
50
+ );
51
+ if (asChild) {
52
+ return /* @__PURE__ */ jsx(
53
+ Slot,
54
+ {
55
+ ...rest,
56
+ ref,
57
+ className: rootClassName,
58
+ onClick: isInteractive ? onClick : void 0,
59
+ onKeyDown: isInteractive ? handleKeyDown : onKeyDown,
60
+ "aria-disabled": disabled || void 0,
61
+ children
62
+ }
63
+ );
64
+ }
65
+ if (loading) {
66
+ return /* @__PURE__ */ jsx("div", { ...rest, ref, className: rootClassName, "aria-busy": "true", "aria-label": "Loading", children: /* @__PURE__ */ jsx("div", { className: "ods-card__skeleton", "data-ods-animate": "shimmer" }) });
67
+ }
68
+ return /* @__PURE__ */ jsx(
69
+ motion.div,
70
+ {
71
+ ...rest,
72
+ ref,
73
+ onClick: isInteractive ? onClick : void 0,
74
+ onKeyDown: isInteractive ? handleKeyDown : onKeyDown,
75
+ className: rootClassName,
76
+ whileHover: (hoverable || isInteractive) && !reducedMotion ? { y: -2, transition: { duration: 0.15 } } : void 0,
77
+ whileTap: isInteractive && !reducedMotion ? { scale: 0.99 } : void 0,
78
+ role: isInteractive ? "button" : rest.role,
79
+ tabIndex: isInteractive ? rest.tabIndex ?? 0 : rest.tabIndex,
80
+ "aria-disabled": disabled || void 0,
81
+ children
82
+ }
83
+ );
84
+ });
85
+ Card.displayName = "Card";
86
+ var CardHeader = forwardRef(function CardHeader2({ className, children, ...rest }, ref) {
87
+ return /* @__PURE__ */ jsx("div", { ...rest, ref, className: cn("ods-card__header", className), children });
88
+ });
89
+ CardHeader.displayName = "Card.Header";
90
+ var CardBody = forwardRef(function CardBody2({ className, children, ...rest }, ref) {
91
+ return /* @__PURE__ */ jsx("div", { ...rest, ref, className: cn("ods-card__body", className), children });
92
+ });
93
+ CardBody.displayName = "Card.Body";
94
+ var CardFooter = forwardRef(function CardFooter2({ className, children, ...rest }, ref) {
95
+ return /* @__PURE__ */ jsx("div", { ...rest, ref, className: cn("ods-card__footer", className), children });
96
+ });
97
+ CardFooter.displayName = "Card.Footer";
98
+ var CardTitle = forwardRef(function CardTitle2({ as: Comp = "h3", className, children, ...rest }, ref) {
99
+ return /* @__PURE__ */ jsx(
100
+ Comp,
101
+ {
102
+ ...rest,
103
+ ref,
104
+ className: cn("ods-card__title", className),
105
+ children
106
+ }
107
+ );
108
+ });
109
+ CardTitle.displayName = "Card.Title";
110
+ var CardDescription = forwardRef(
111
+ function CardDescription2({ className, children, ...rest }, ref) {
112
+ return /* @__PURE__ */ jsx("p", { ...rest, ref, className: cn("ods-card__description", className), children });
113
+ }
114
+ );
115
+ CardDescription.displayName = "Card.Description";
116
+ Card.Header = CardHeader;
117
+ Card.Body = CardBody;
118
+ Card.Footer = CardFooter;
119
+ Card.Title = CardTitle;
120
+ Card.Description = CardDescription;
121
+
122
+ // src/components/Avatar/Avatar.tsx
123
+ import {
124
+ forwardRef as forwardRef2,
125
+ useCallback,
126
+ useMemo,
127
+ useState
128
+ } from "react";
129
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
130
+ var PALETTE_SIZE = 12;
131
+ function djb2(str) {
132
+ let h = 5381;
133
+ for (let i = 0; i < str.length; i++) h = (h << 5) + h + str.charCodeAt(i);
134
+ return h >>> 0;
135
+ }
136
+ function paletteIndexFor(seed) {
137
+ return djb2(seed) % PALETTE_SIZE;
138
+ }
139
+ var AVATAR_PALETTE_SIZE = PALETTE_SIZE;
140
+ function avatarPaletteIndex(seed) {
141
+ return paletteIndexFor(seed);
142
+ }
143
+ function normalizeInitials(raw) {
144
+ const trimmed = raw.trim();
145
+ if (!trimmed) return "";
146
+ const tokens = trimmed.split(/\s+/).filter(Boolean);
147
+ if (tokens.length >= 2) {
148
+ return (tokens[0].charAt(0) + tokens[1].charAt(0)).toUpperCase();
149
+ }
150
+ return trimmed.slice(0, 2).toUpperCase();
151
+ }
152
+ var STATUS_DEFAULT_LABEL = {
153
+ online: "Online",
154
+ offline: "Offline",
155
+ busy: "Busy",
156
+ away: "Away"
157
+ };
158
+ var Avatar = forwardRef2(function Avatar2({
159
+ src,
160
+ alt,
161
+ initials,
162
+ icon,
163
+ fallback,
164
+ seed,
165
+ palette,
166
+ size = "md",
167
+ shape = "circle",
168
+ status,
169
+ statusLabel,
170
+ onClick,
171
+ imgLoading = "lazy",
172
+ referrerPolicy,
173
+ className,
174
+ ...rest
175
+ }, ref) {
176
+ const [imgFailed, setImgFailed] = useState(false);
177
+ const handleImgError = useCallback(() => setImgFailed(true), []);
178
+ const showImage = Boolean(src) && !imgFailed;
179
+ const normalizedInitials = useMemo(
180
+ () => initials ? normalizeInitials(initials) : "",
181
+ [initials]
182
+ );
183
+ const paletteIdx = useMemo(() => {
184
+ if (palette !== void 0) {
185
+ return (Math.trunc(palette) % PALETTE_SIZE + PALETTE_SIZE) % PALETTE_SIZE;
186
+ }
187
+ const resolved = seed ?? alt ?? initials ?? "?";
188
+ return paletteIndexFor(resolved);
189
+ }, [palette, seed, alt, initials]);
190
+ const baseName = alt || normalizedInitials || "Avatar";
191
+ const announcedStatus = status ? statusLabel ?? STATUS_DEFAULT_LABEL[status] : "";
192
+ const accessibleName = announcedStatus ? `${baseName}, ${announcedStatus}` : baseName;
193
+ const isClickable = Boolean(onClick);
194
+ const handleKeyDown = (e) => {
195
+ if (!isClickable) return;
196
+ if ((e.key === "Enter" || e.key === " ") && !e.repeat) {
197
+ e.preventDefault();
198
+ onClick?.();
199
+ }
200
+ };
201
+ const rootClassName = cn(
202
+ "ods-avatar",
203
+ `ods-avatar--${size}`,
204
+ `ods-avatar--${shape}`,
205
+ isClickable && "ods-avatar--clickable",
206
+ className
207
+ );
208
+ return /* @__PURE__ */ jsxs(
209
+ "div",
210
+ {
211
+ ...rest,
212
+ ref,
213
+ className: rootClassName,
214
+ role: isClickable ? "button" : "img",
215
+ "aria-label": accessibleName,
216
+ tabIndex: isClickable ? 0 : void 0,
217
+ onClick,
218
+ onKeyDown: isClickable ? handleKeyDown : void 0,
219
+ "data-status": status,
220
+ children: [
221
+ /* @__PURE__ */ jsx2("span", { className: "ods-avatar__inner", "data-palette": paletteIdx, children: showImage ? /* @__PURE__ */ jsx2(
222
+ "img",
223
+ {
224
+ src,
225
+ alt: "",
226
+ className: "ods-avatar__image",
227
+ loading: imgLoading,
228
+ decoding: "async",
229
+ referrerPolicy,
230
+ onError: handleImgError,
231
+ draggable: false
232
+ }
233
+ ) : icon ? /* @__PURE__ */ jsx2("span", { className: "ods-avatar__icon", "aria-hidden": "true", children: icon }) : normalizedInitials ? /* @__PURE__ */ jsx2("span", { className: "ods-avatar__initials", "aria-hidden": "true", children: normalizedInitials }) : /* @__PURE__ */ jsx2("span", { className: "ods-avatar__initials", "aria-hidden": "true", children: fallback ?? "?" }) }),
234
+ status && // Decorative — the textual status is folded into the wrapper's
235
+ // aria-label above. `aria-hidden` keeps AT from double-announcing.
236
+ /* @__PURE__ */ jsx2(
237
+ "span",
238
+ {
239
+ className: cn("ods-avatar__status", `ods-avatar__status--${status}`),
240
+ "aria-hidden": "true"
241
+ }
242
+ )
243
+ ]
244
+ }
245
+ );
246
+ });
247
+ Avatar.displayName = "Avatar";
248
+ var AvatarStack = forwardRef2(function AvatarStack2({ children, max, size = "md", renderOverflow, direction = "ltr", className, ...rest }, ref) {
249
+ const arr = Array.isArray(children) ? children : [children];
250
+ const visible = max && arr.length > max ? arr.slice(0, max) : arr;
251
+ const overflow = max && arr.length > max ? arr.length - max : 0;
252
+ return /* @__PURE__ */ jsxs(
253
+ "div",
254
+ {
255
+ ...rest,
256
+ ref,
257
+ className: cn("ods-avatar-stack", `ods-avatar-stack--${direction}`, className),
258
+ children: [
259
+ visible,
260
+ overflow > 0 && (renderOverflow ? renderOverflow(overflow) : /* @__PURE__ */ jsx2(
261
+ "div",
262
+ {
263
+ className: cn(
264
+ "ods-avatar",
265
+ `ods-avatar--${size}`,
266
+ "ods-avatar--circle",
267
+ "ods-avatar-stack__overflow"
268
+ ),
269
+ role: "img",
270
+ "aria-label": `${overflow} more`,
271
+ children: /* @__PURE__ */ jsx2("span", { className: "ods-avatar__inner", children: /* @__PURE__ */ jsxs("span", { className: "ods-avatar__initials", "aria-hidden": "true", children: [
272
+ "+",
273
+ overflow
274
+ ] }) })
275
+ }
276
+ ))
277
+ ]
278
+ }
279
+ );
280
+ });
281
+ AvatarStack.displayName = "AvatarStack";
282
+
283
+ // src/components/BlogCard/BlogCard.tsx
284
+ import { forwardRef as forwardRef3, useId } from "react";
285
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
286
+ var BlogCard = forwardRef3(function BlogCard2({
287
+ cover,
288
+ coverAspect = "16/9",
289
+ category,
290
+ tags,
291
+ meta,
292
+ readingTime,
293
+ title,
294
+ titleAs = "h3",
295
+ description,
296
+ author,
297
+ footer,
298
+ radius = "md",
299
+ orientation = "vertical",
300
+ href,
301
+ onClick,
302
+ id: providedId,
303
+ className,
304
+ ...rest
305
+ }, ref) {
306
+ const reactId = useId();
307
+ const baseId = providedId ?? `ods-blog-card-${reactId}`;
308
+ const titleId = `${baseId}-title`;
309
+ const descId = description ? `${baseId}-desc` : void 0;
310
+ const tagList = tags ?? (category ? [category] : []);
311
+ const body = /* @__PURE__ */ jsxs2(Fragment, { children: [
312
+ cover && /* @__PURE__ */ jsx3(
313
+ "div",
314
+ {
315
+ className: cn(
316
+ "ods-blog-card__cover",
317
+ `ods-blog-card__cover--aspect-${coverAspect.replace("/", "-")}`
318
+ ),
319
+ "aria-hidden": "true",
320
+ children: cover
321
+ }
322
+ ),
323
+ /* @__PURE__ */ jsxs2("div", { className: "ods-blog-card__body", children: [
324
+ (tagList.length > 0 || meta || readingTime) && /* @__PURE__ */ jsxs2("div", { className: "ods-blog-card__meta", children: [
325
+ tagList.length > 0 && /* @__PURE__ */ jsx3("span", { className: "ods-blog-card__tags", children: tagList.map((t, i) => /* @__PURE__ */ jsx3("span", { className: "ods-blog-card__tag", children: t }, i)) }),
326
+ meta && /* @__PURE__ */ jsx3("span", { className: "ods-blog-card__date", children: meta }),
327
+ readingTime && /* @__PURE__ */ jsx3("span", { className: "ods-blog-card__reading", children: readingTime })
328
+ ] }),
329
+ /* @__PURE__ */ jsx3(Card.Title, { as: titleAs, id: titleId, className: "ods-blog-card__title", children: title }),
330
+ description && /* @__PURE__ */ jsx3(Card.Description, { id: descId, className: "ods-blog-card__desc", children: description }),
331
+ (author || footer) && /* @__PURE__ */ jsxs2("div", { className: "ods-blog-card__footer", children: [
332
+ author && /* @__PURE__ */ jsxs2("div", { className: "ods-blog-card__author", children: [
333
+ author.avatar && /* @__PURE__ */ jsx3(
334
+ Avatar,
335
+ {
336
+ size: "sm",
337
+ src: author.avatar.src,
338
+ initials: author.avatar.initials,
339
+ seed: author.avatar.seed,
340
+ palette: author.avatar.palette,
341
+ alt: author.avatar.alt ?? (typeof author.name === "string" ? author.name : void 0)
342
+ }
343
+ ),
344
+ /* @__PURE__ */ jsxs2("div", { className: "ods-blog-card__author-text", children: [
345
+ /* @__PURE__ */ jsx3("span", { className: "ods-blog-card__author-name", children: author.name }),
346
+ author.byline && /* @__PURE__ */ jsx3("span", { className: "ods-blog-card__author-byline", children: author.byline })
347
+ ] })
348
+ ] }),
349
+ footer && /* @__PURE__ */ jsx3("div", { className: "ods-blog-card__action", children: footer })
350
+ ] })
351
+ ] })
352
+ ] });
353
+ if (href) {
354
+ return /* @__PURE__ */ jsx3(
355
+ Card,
356
+ {
357
+ asChild: true,
358
+ radius,
359
+ padding: "none",
360
+ className: cn(
361
+ "ods-blog-card",
362
+ `ods-blog-card--${orientation}`,
363
+ "ods-blog-card--interactive",
364
+ className
365
+ ),
366
+ "aria-labelledby": titleId,
367
+ "aria-describedby": descId,
368
+ children: /* @__PURE__ */ jsx3(
369
+ "a",
370
+ {
371
+ ...rest,
372
+ ref,
373
+ href,
374
+ id: baseId,
375
+ onClick,
376
+ children: body
377
+ }
378
+ )
379
+ }
380
+ );
381
+ }
382
+ return /* @__PURE__ */ jsx3(
383
+ Card,
384
+ {
385
+ ...rest,
386
+ ref,
387
+ id: baseId,
388
+ radius,
389
+ padding: "none",
390
+ onClick,
391
+ className: cn(
392
+ "ods-blog-card",
393
+ `ods-blog-card--${orientation}`,
394
+ onClick && "ods-blog-card--interactive",
395
+ className
396
+ ),
397
+ "aria-labelledby": titleId,
398
+ "aria-describedby": descId,
399
+ children: body
400
+ }
401
+ );
402
+ });
403
+ BlogCard.displayName = "BlogCard";
404
+
405
+ // src/components/CountUp/CountUp.tsx
406
+ import {
407
+ forwardRef as forwardRef4,
408
+ useEffect,
409
+ useRef,
410
+ useState as useState2
411
+ } from "react";
412
+ import { jsxs as jsxs3 } from "react/jsx-runtime";
413
+ var easeLinear = (t) => t;
414
+ var easeOutCubic = (t) => 1 - (1 - t) ** 3;
415
+ var easeOutQuart = (t) => 1 - (1 - t) ** 4;
416
+ var easeOutExpo = (t) => t === 1 ? 1 : 1 - 2 ** (-10 * t);
417
+ var CountUp = forwardRef4(function CountUp2({
418
+ value,
419
+ from = 0,
420
+ duration = 800,
421
+ easing = easeOutCubic,
422
+ decimals = 0,
423
+ formatValue,
424
+ prefix,
425
+ suffix,
426
+ delay = 0,
427
+ disableAnimation = false,
428
+ onComplete,
429
+ className,
430
+ ...rest
431
+ }, ref) {
432
+ const [n, setN] = useState2(disableAnimation ? value : from);
433
+ const lastRendered = useRef(disableAnimation ? value : from);
434
+ useEffect(() => {
435
+ const reduced = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
436
+ if (disableAnimation || reduced) {
437
+ setN(value);
438
+ lastRendered.current = value;
439
+ onComplete?.();
440
+ return;
441
+ }
442
+ const startValue = lastRendered.current;
443
+ const delta = value - startValue;
444
+ if (delta === 0) return;
445
+ let raf = null;
446
+ let timeoutId = null;
447
+ let startTime = null;
448
+ let cancelled = false;
449
+ const tick = (ts) => {
450
+ if (cancelled) return;
451
+ if (startTime === null) startTime = ts;
452
+ const t = Math.min(1, (ts - startTime) / Math.max(1, duration));
453
+ const eased = easing(t);
454
+ const current = startValue + delta * eased;
455
+ setN(current);
456
+ lastRendered.current = current;
457
+ if (t < 1) {
458
+ raf = requestAnimationFrame(tick);
459
+ } else {
460
+ lastRendered.current = value;
461
+ setN(value);
462
+ onComplete?.();
463
+ }
464
+ };
465
+ const start = () => {
466
+ raf = requestAnimationFrame(tick);
467
+ };
468
+ if (delay > 0) {
469
+ timeoutId = window.setTimeout(start, delay);
470
+ } else {
471
+ start();
472
+ }
473
+ return () => {
474
+ cancelled = true;
475
+ if (raf !== null) cancelAnimationFrame(raf);
476
+ if (timeoutId !== null) window.clearTimeout(timeoutId);
477
+ };
478
+ }, [value, duration, delay, disableAnimation]);
479
+ const display = formatValue ? formatValue(n) : n.toFixed(decimals);
480
+ return /* @__PURE__ */ jsxs3(
481
+ "span",
482
+ {
483
+ ...rest,
484
+ ref,
485
+ className: cn("ods-count-up", className),
486
+ "aria-live": "polite",
487
+ "aria-atomic": "true",
488
+ children: [
489
+ prefix,
490
+ display,
491
+ suffix
492
+ ]
493
+ }
494
+ );
495
+ });
496
+ CountUp.displayName = "CountUp";
497
+
498
+ // src/hooks/useTextareaCommands.ts
499
+ import {
500
+ useCallback as useCallback2,
501
+ useEffect as useEffect2,
502
+ useMemo as useMemo2,
503
+ useRef as useRef2,
504
+ useState as useState3
505
+ } from "react";
506
+ function findOpenTrigger(value, caret, trigger) {
507
+ let i = caret - 1;
508
+ while (i >= 0) {
509
+ const ch = value[i];
510
+ if (ch === "\n" || ch === " " || ch === " ") return null;
511
+ if (value.startsWith(trigger, i)) {
512
+ const before = i === 0 ? "" : value[i - 1];
513
+ if (i === 0 || before === " " || before === "\n" || before === " ") {
514
+ return {
515
+ triggerIndex: i,
516
+ query: value.slice(i + trigger.length, caret)
517
+ };
518
+ }
519
+ return null;
520
+ }
521
+ i--;
522
+ }
523
+ return null;
524
+ }
525
+ function getCaretRect(textarea, caret) {
526
+ if (typeof document === "undefined") return null;
527
+ const mirror = document.createElement("div");
528
+ const styles = window.getComputedStyle(textarea);
529
+ for (const prop of [
530
+ "boxSizing",
531
+ "width",
532
+ "fontFamily",
533
+ "fontSize",
534
+ "fontWeight",
535
+ "fontStyle",
536
+ "letterSpacing",
537
+ "lineHeight",
538
+ "paddingTop",
539
+ "paddingRight",
540
+ "paddingBottom",
541
+ "paddingLeft",
542
+ "borderTopWidth",
543
+ "borderRightWidth",
544
+ "borderBottomWidth",
545
+ "borderLeftWidth",
546
+ "textTransform",
547
+ "wordSpacing",
548
+ "tabSize",
549
+ "whiteSpace"
550
+ ]) {
551
+ mirror.style[prop] = styles[prop];
552
+ }
553
+ mirror.style.position = "absolute";
554
+ mirror.style.visibility = "hidden";
555
+ mirror.style.overflow = "hidden";
556
+ mirror.style.top = "0";
557
+ mirror.style.left = "0";
558
+ mirror.style.whiteSpace = "pre-wrap";
559
+ mirror.style.wordWrap = "break-word";
560
+ mirror.textContent = textarea.value.slice(0, caret);
561
+ const marker = document.createElement("span");
562
+ marker.textContent = "\u200B";
563
+ mirror.appendChild(marker);
564
+ document.body.appendChild(mirror);
565
+ const taRect = textarea.getBoundingClientRect();
566
+ const markerRect = marker.getBoundingClientRect();
567
+ const mirrorRect = mirror.getBoundingClientRect();
568
+ const x = taRect.left + (markerRect.left - mirrorRect.left) - textarea.scrollLeft;
569
+ const y = taRect.top + (markerRect.top - mirrorRect.top) - textarea.scrollTop;
570
+ const out = new DOMRect(x, y, 0, markerRect.height || 16);
571
+ document.body.removeChild(mirror);
572
+ return out;
573
+ }
574
+ function useTextareaCommands({
575
+ textareaRef,
576
+ value,
577
+ onChange,
578
+ commands,
579
+ trigger = "/",
580
+ openOnEmptyTrigger = true,
581
+ maxItems = 8
582
+ }) {
583
+ const [isOpen, setIsOpen] = useState3(false);
584
+ const [query, setQuery] = useState3("");
585
+ const [activeIndex, setActiveIndex] = useState3(0);
586
+ const [triggerIndex, setTriggerIndex] = useState3(null);
587
+ const [caretRect, setCaretRect] = useState3(null);
588
+ const dismissedAtRef = useRef2(null);
589
+ const items = useMemo2(() => {
590
+ const q = query.trim().toLowerCase();
591
+ if (!q) return commands.slice(0, maxItems);
592
+ return commands.filter((c) => {
593
+ const hay = [
594
+ typeof c.label === "string" ? c.label : "",
595
+ typeof c.description === "string" ? c.description : "",
596
+ c.id,
597
+ ...c.keywords ?? []
598
+ ].join(" ").toLowerCase();
599
+ return hay.includes(q);
600
+ }).slice(0, maxItems);
601
+ }, [commands, query, maxItems]);
602
+ useEffect2(() => {
603
+ const ta = textareaRef.current;
604
+ if (!ta) return;
605
+ const caret = ta.selectionStart ?? 0;
606
+ const dismissedAt = dismissedAtRef.current;
607
+ if (dismissedAt && dismissedAt.value === value && dismissedAt.caret === caret) {
608
+ return;
609
+ }
610
+ const found = findOpenTrigger(value, caret, trigger);
611
+ if (!found) {
612
+ if (isOpen) setIsOpen(false);
613
+ setTriggerIndex(null);
614
+ return;
615
+ }
616
+ if (dismissedAt) dismissedAtRef.current = null;
617
+ if (found.query.length > 0 || openOnEmptyTrigger) {
618
+ setQuery(found.query);
619
+ setTriggerIndex(found.triggerIndex);
620
+ setIsOpen(true);
621
+ setActiveIndex(0);
622
+ setCaretRect(getCaretRect(ta, caret));
623
+ }
624
+ }, [value, trigger, openOnEmptyTrigger, isOpen, textareaRef]);
625
+ const commit = useCallback2(
626
+ (cmd) => {
627
+ const ta = textareaRef.current;
628
+ if (!ta || triggerIndex == null) return;
629
+ const insertText = typeof cmd.insert === "function" ? cmd.insert(query) : cmd.insert;
630
+ const caret = ta.selectionStart ?? value.length;
631
+ const before = value.slice(0, triggerIndex);
632
+ const after = value.slice(caret);
633
+ const next = `${before}${insertText}${after}`;
634
+ dismissedAtRef.current = {
635
+ value,
636
+ caret
637
+ };
638
+ onChange(next);
639
+ setIsOpen(false);
640
+ setTriggerIndex(null);
641
+ requestAnimationFrame(() => {
642
+ const pos = before.length + insertText.length;
643
+ ta.focus();
644
+ ta.setSelectionRange(pos, pos);
645
+ });
646
+ },
647
+ [textareaRef, triggerIndex, query, value, onChange]
648
+ );
649
+ const dismiss = useCallback2(() => {
650
+ const ta = textareaRef.current;
651
+ dismissedAtRef.current = {
652
+ value,
653
+ caret: ta?.selectionStart ?? value.length
654
+ };
655
+ setIsOpen(false);
656
+ setTriggerIndex(null);
657
+ }, [textareaRef, value]);
658
+ const onKeyDown = useCallback2(
659
+ (e) => {
660
+ if (!isOpen) return false;
661
+ if (e.key === "ArrowDown") {
662
+ e.preventDefault();
663
+ setActiveIndex((i) => Math.min(items.length - 1, i + 1));
664
+ return true;
665
+ }
666
+ if (e.key === "ArrowUp") {
667
+ e.preventDefault();
668
+ setActiveIndex((i) => Math.max(0, i - 1));
669
+ return true;
670
+ }
671
+ if (e.key === "Enter" || e.key === "Tab") {
672
+ const pick = items[activeIndex];
673
+ if (pick) {
674
+ e.preventDefault();
675
+ commit(pick);
676
+ return true;
677
+ }
678
+ }
679
+ if (e.key === "Escape") {
680
+ e.preventDefault();
681
+ dismiss();
682
+ return true;
683
+ }
684
+ return false;
685
+ },
686
+ [isOpen, items, activeIndex, commit, dismiss]
687
+ );
688
+ return {
689
+ isOpen,
690
+ query,
691
+ activeIndex,
692
+ items,
693
+ onKeyDown,
694
+ dismiss,
695
+ commit,
696
+ caretRect
697
+ };
698
+ }
699
+
700
+ // src/hooks/useTextareaSelection.ts
701
+ import { useCallback as useCallback3, useEffect as useEffect3, useState as useState4 } from "react";
702
+ function getSelectionRect(textarea, start, end) {
703
+ if (typeof document === "undefined") return null;
704
+ if (start === end) return null;
705
+ const mirror = document.createElement("div");
706
+ const styles = window.getComputedStyle(textarea);
707
+ for (const prop of [
708
+ "boxSizing",
709
+ "width",
710
+ "fontFamily",
711
+ "fontSize",
712
+ "fontWeight",
713
+ "fontStyle",
714
+ "letterSpacing",
715
+ "lineHeight",
716
+ "paddingTop",
717
+ "paddingRight",
718
+ "paddingBottom",
719
+ "paddingLeft",
720
+ "borderTopWidth",
721
+ "borderRightWidth",
722
+ "borderBottomWidth",
723
+ "borderLeftWidth",
724
+ "textTransform",
725
+ "wordSpacing",
726
+ "tabSize",
727
+ "whiteSpace"
728
+ ]) {
729
+ mirror.style[prop] = styles[prop];
730
+ }
731
+ mirror.style.position = "absolute";
732
+ mirror.style.visibility = "hidden";
733
+ mirror.style.overflow = "hidden";
734
+ mirror.style.top = "0";
735
+ mirror.style.left = "0";
736
+ mirror.style.whiteSpace = "pre-wrap";
737
+ mirror.style.wordWrap = "break-word";
738
+ const pre = document.createTextNode(textarea.value.slice(0, start));
739
+ const range = document.createElement("span");
740
+ range.textContent = textarea.value.slice(start, end) || "\u200B";
741
+ const post = document.createTextNode(textarea.value.slice(end));
742
+ mirror.appendChild(pre);
743
+ mirror.appendChild(range);
744
+ mirror.appendChild(post);
745
+ document.body.appendChild(mirror);
746
+ const taRect = textarea.getBoundingClientRect();
747
+ const rangeRect = range.getBoundingClientRect();
748
+ const mirrorRect = mirror.getBoundingClientRect();
749
+ const out = new DOMRect(
750
+ taRect.left + (rangeRect.left - mirrorRect.left) - textarea.scrollLeft,
751
+ taRect.top + (rangeRect.top - mirrorRect.top) - textarea.scrollTop,
752
+ rangeRect.width,
753
+ rangeRect.height
754
+ );
755
+ document.body.removeChild(mirror);
756
+ return out;
757
+ }
758
+ function useTextareaSelection({
759
+ textareaRef,
760
+ value,
761
+ onChange
762
+ }) {
763
+ const [start, setStart] = useState4(0);
764
+ const [end, setEnd] = useState4(0);
765
+ const [rect, setRect] = useState4(null);
766
+ useEffect3(() => {
767
+ if (typeof document === "undefined") return;
768
+ const handler = () => {
769
+ const ta = textareaRef.current;
770
+ if (!ta || document.activeElement !== ta) {
771
+ setStart(0);
772
+ setEnd(0);
773
+ setRect(null);
774
+ return;
775
+ }
776
+ const s = ta.selectionStart ?? 0;
777
+ const e = ta.selectionEnd ?? 0;
778
+ setStart(s);
779
+ setEnd(e);
780
+ setRect(s !== e ? getSelectionRect(ta, s, e) : null);
781
+ };
782
+ document.addEventListener("selectionchange", handler);
783
+ return () => document.removeEventListener("selectionchange", handler);
784
+ }, [textareaRef]);
785
+ const active = start !== end;
786
+ const text = active ? value.slice(start, end) : "";
787
+ const writeToClipboard = useCallback3(async (str) => {
788
+ try {
789
+ if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
790
+ await navigator.clipboard.writeText(str);
791
+ return true;
792
+ }
793
+ } catch {
794
+ }
795
+ try {
796
+ const tmp = document.createElement("textarea");
797
+ tmp.value = str;
798
+ tmp.style.position = "fixed";
799
+ tmp.style.left = "-9999px";
800
+ document.body.appendChild(tmp);
801
+ tmp.select();
802
+ const ok = document.execCommand("copy");
803
+ document.body.removeChild(tmp);
804
+ return ok;
805
+ } catch {
806
+ return false;
807
+ }
808
+ }, []);
809
+ const copy = useCallback3(async () => {
810
+ if (!active) return false;
811
+ return writeToClipboard(text);
812
+ }, [active, text, writeToClipboard]);
813
+ const replace = useCallback3(
814
+ (str) => {
815
+ const ta = textareaRef.current;
816
+ if (!ta) return;
817
+ const next = value.slice(0, start) + str + value.slice(end);
818
+ onChange(next);
819
+ requestAnimationFrame(() => {
820
+ ta.focus();
821
+ const caret = start + str.length;
822
+ ta.setSelectionRange(caret, caret);
823
+ });
824
+ },
825
+ [textareaRef, value, start, end, onChange]
826
+ );
827
+ const cut = useCallback3(async () => {
828
+ if (!active) return false;
829
+ const ok = await writeToClipboard(text);
830
+ if (ok) replace("");
831
+ return ok;
832
+ }, [active, text, writeToClipboard, replace]);
833
+ const wrap = useCallback3(
834
+ (open, close) => {
835
+ const ta = textareaRef.current;
836
+ if (!ta) return;
837
+ const closing = close ?? open;
838
+ const before = value.slice(0, start);
839
+ const sel = value.slice(start, end);
840
+ const after = value.slice(end);
841
+ const next = `${before}${open}${sel}${closing}${after}`;
842
+ onChange(next);
843
+ requestAnimationFrame(() => {
844
+ ta.focus();
845
+ const newStart = start;
846
+ const newEnd = end + open.length + closing.length;
847
+ ta.setSelectionRange(newStart, newEnd);
848
+ });
849
+ },
850
+ [textareaRef, value, start, end, onChange]
851
+ );
852
+ return {
853
+ active,
854
+ text,
855
+ start,
856
+ end,
857
+ rect,
858
+ copy,
859
+ cut,
860
+ wrap,
861
+ replace
862
+ };
863
+ }
864
+
865
+ // src/hooks/useTextareaTools.tsx
866
+ import {
867
+ CodeIcon,
868
+ HeadingIcon,
869
+ ListBulletedIcon,
870
+ ListNumberedIcon,
871
+ QuotesIcon,
872
+ RedoIcon,
873
+ TextBoldIcon,
874
+ TextItalicIcon,
875
+ TextLinkIcon,
876
+ TextStrikethroughIcon,
877
+ UndoIcon
878
+ } from "@octaviaflow/icons";
879
+ import { useCallback as useCallback4, useMemo as useMemo3, useRef as useRef3 } from "react";
880
+ import { jsx as jsx4 } from "react/jsx-runtime";
881
+ function useTextareaTools({
882
+ textareaRef,
883
+ value,
884
+ onChange,
885
+ tools
886
+ }) {
887
+ const valueRef = useRef3(value);
888
+ valueRef.current = value;
889
+ const helpers = useMemo3(() => {
890
+ const getTa = () => textareaRef.current;
891
+ const getSelection = () => {
892
+ const ta = getTa();
893
+ const s = ta?.selectionStart ?? 0;
894
+ const e = ta?.selectionEnd ?? 0;
895
+ return {
896
+ text: valueRef.current.slice(s, e),
897
+ start: s,
898
+ end: e,
899
+ active: s !== e
900
+ };
901
+ };
902
+ const setValue = (next) => onChange(next);
903
+ const replace = (text) => {
904
+ const ta = getTa();
905
+ if (!ta) return;
906
+ const { start, end } = getSelection();
907
+ const next = valueRef.current.slice(0, start) + text + valueRef.current.slice(end);
908
+ onChange(next);
909
+ requestAnimationFrame(() => {
910
+ ta.focus();
911
+ const caret = start + text.length;
912
+ ta.setSelectionRange(caret, caret);
913
+ });
914
+ };
915
+ const insert = (text) => replace(text);
916
+ const wrap = (open, close) => {
917
+ const ta = getTa();
918
+ if (!ta) return;
919
+ const closing = close ?? open;
920
+ const { start, end } = getSelection();
921
+ const sel = valueRef.current.slice(start, end);
922
+ const next = valueRef.current.slice(0, start) + open + sel + closing + valueRef.current.slice(end);
923
+ onChange(next);
924
+ requestAnimationFrame(() => {
925
+ ta.focus();
926
+ if (start === end) {
927
+ const caret = start + open.length;
928
+ ta.setSelectionRange(caret, caret);
929
+ } else {
930
+ ta.setSelectionRange(start, end + open.length + closing.length);
931
+ }
932
+ });
933
+ };
934
+ const prependLines = (prefix) => {
935
+ const ta = getTa();
936
+ if (!ta) return;
937
+ const { start, end } = getSelection();
938
+ const v = valueRef.current;
939
+ const lineStart = v.lastIndexOf("\n", start - 1) + 1;
940
+ const lineEnd = (() => {
941
+ const idx = v.indexOf("\n", end);
942
+ return idx === -1 ? v.length : idx;
943
+ })();
944
+ const block = v.slice(lineStart, lineEnd);
945
+ const updated = block.split("\n").map((line) => `${prefix}${line}`).join("\n");
946
+ const next = v.slice(0, lineStart) + updated + v.slice(lineEnd);
947
+ onChange(next);
948
+ requestAnimationFrame(() => {
949
+ ta.focus();
950
+ ta.setSelectionRange(lineStart, lineStart + updated.length);
951
+ });
952
+ };
953
+ const undo = () => {
954
+ try {
955
+ getTa()?.focus();
956
+ document.execCommand("undo");
957
+ } catch {
958
+ }
959
+ };
960
+ const redo = () => {
961
+ try {
962
+ getTa()?.focus();
963
+ document.execCommand("redo");
964
+ } catch {
965
+ }
966
+ };
967
+ return {
968
+ get value() {
969
+ return valueRef.current;
970
+ },
971
+ get selection() {
972
+ return getSelection();
973
+ },
974
+ setValue,
975
+ replace,
976
+ insert,
977
+ wrap,
978
+ prependLines,
979
+ undo,
980
+ redo,
981
+ getTextarea: getTa
982
+ };
983
+ }, [textareaRef, onChange]);
984
+ const visibleTools = useMemo3(
985
+ () => tools.filter((t) => t.isVisible ? t.isVisible(helpers) : true),
986
+ [tools, helpers]
987
+ );
988
+ const runTool = useCallback4(
989
+ async (id) => {
990
+ const tool = tools.find((t) => t.id === id);
991
+ if (!tool || tool.kind === "divider") return;
992
+ await tool.onAction?.(helpers);
993
+ },
994
+ [tools, helpers]
995
+ );
996
+ return { tools: visibleTools, runTool, helpers };
997
+ }
998
+ var wrapTool = (id, open, close, label, icon, title) => ({
999
+ id,
1000
+ label,
1001
+ icon,
1002
+ title,
1003
+ onAction: (h) => h.wrap(open, close)
1004
+ });
1005
+ var prependLineTool = (id, prefix, label, icon, title) => ({
1006
+ id,
1007
+ label,
1008
+ icon,
1009
+ title,
1010
+ onAction: (h) => h.prependLines(prefix)
1011
+ });
1012
+ var textareaTools = {
1013
+ bold: () => wrapTool("bold", "**", "**", "Bold", /* @__PURE__ */ jsx4(TextBoldIcon, {}), "Bold (\u2318B)"),
1014
+ italic: () => wrapTool("italic", "*", "*", "Italic", /* @__PURE__ */ jsx4(TextItalicIcon, {}), "Italic (\u2318I)"),
1015
+ strikethrough: () => wrapTool("strike", "~~", "~~", "Strikethrough", /* @__PURE__ */ jsx4(TextStrikethroughIcon, {}), "Strikethrough"),
1016
+ code: () => wrapTool("code", "`", "`", "Code", /* @__PURE__ */ jsx4(CodeIcon, {}), "Inline code"),
1017
+ codeBlock: () => ({
1018
+ id: "code-block",
1019
+ label: "Code block",
1020
+ icon: /* @__PURE__ */ jsx4(CodeIcon, {}),
1021
+ title: "Code block",
1022
+ onAction: (h) => h.wrap("```\n", "\n```")
1023
+ }),
1024
+ link: () => ({
1025
+ id: "link",
1026
+ label: "Link",
1027
+ icon: /* @__PURE__ */ jsx4(TextLinkIcon, {}),
1028
+ title: "Insert link",
1029
+ onAction: (h) => {
1030
+ const sel = h.selection;
1031
+ const text = sel.active ? sel.text : "link text";
1032
+ h.replace(`[${text}](https://)`);
1033
+ }
1034
+ }),
1035
+ /** Heading. Defaults to H2. Pass a `level` (1–6) to override. */
1036
+ heading: (level = 2) => prependLineTool(
1037
+ `heading-${level}`,
1038
+ `${"#".repeat(level)} `,
1039
+ `H${level}`,
1040
+ /* @__PURE__ */ jsx4(HeadingIcon, {}),
1041
+ `Heading ${level}`
1042
+ ),
1043
+ bulletList: () => prependLineTool("ul", "- ", "Bullet list", /* @__PURE__ */ jsx4(ListBulletedIcon, {}), "Bullet list"),
1044
+ numberedList: () => prependLineTool("ol", "1. ", "Numbered list", /* @__PURE__ */ jsx4(ListNumberedIcon, {}), "Numbered list"),
1045
+ quote: () => prependLineTool("quote", "> ", "Quote", /* @__PURE__ */ jsx4(QuotesIcon, {}), "Quote"),
1046
+ undo: () => ({
1047
+ id: "undo",
1048
+ label: "Undo",
1049
+ icon: /* @__PURE__ */ jsx4(UndoIcon, {}),
1050
+ title: "Undo (\u2318Z)",
1051
+ onAction: (h) => h.undo()
1052
+ }),
1053
+ redo: () => ({
1054
+ id: "redo",
1055
+ label: "Redo",
1056
+ icon: /* @__PURE__ */ jsx4(RedoIcon, {}),
1057
+ title: "Redo (\u2318\u21E7Z)",
1058
+ onAction: (h) => h.redo()
1059
+ }),
1060
+ divider: (id = "divider") => ({
1061
+ id: `${id}-${Math.random().toString(36).slice(2, 8)}`,
1062
+ label: "",
1063
+ kind: "divider"
1064
+ })
1065
+ };
1066
+
1067
+ // src/components/Textarea/Textarea.tsx
1068
+ import { CopyIcon, CutIcon } from "@octaviaflow/icons";
1069
+ import {
1070
+ forwardRef as forwardRef5,
1071
+ useEffect as useEffect4,
1072
+ useId as useId2,
1073
+ useRef as useRef4,
1074
+ useState as useState5
1075
+ } from "react";
1076
+ import { useTextField } from "react-aria";
1077
+ import { createPortal } from "react-dom";
1078
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1079
+ var Textarea = forwardRef5(function Textarea2({
1080
+ label,
1081
+ error = false,
1082
+ errorMessage,
1083
+ helperText,
1084
+ resize = "vertical",
1085
+ autoResize = false,
1086
+ minRows,
1087
+ maxRows,
1088
+ maxHeight,
1089
+ maxWidth,
1090
+ minHeight,
1091
+ minWidth,
1092
+ maxLength,
1093
+ size = "md",
1094
+ rows = 3,
1095
+ disabled = false,
1096
+ className,
1097
+ style: consumerStyle,
1098
+ defaultValue,
1099
+ value,
1100
+ onChange,
1101
+ id: providedId,
1102
+ commands,
1103
+ commandTrigger = "/",
1104
+ selectionToolbar = false,
1105
+ selectionActions,
1106
+ tools,
1107
+ toolbarPosition = "top",
1108
+ ...props
1109
+ }, forwardedRef) {
1110
+ const innerRef = useRef4(null);
1111
+ const setRef = (node) => {
1112
+ innerRef.current = node;
1113
+ if (typeof forwardedRef === "function") forwardedRef(node);
1114
+ else if (forwardedRef) forwardedRef.current = node;
1115
+ };
1116
+ const reactId = useId2();
1117
+ const baseId = providedId ?? `ods-textarea-${reactId}`;
1118
+ const hintId = error && errorMessage || helperText ? `${baseId}-hint` : void 0;
1119
+ const [charCount, setCharCount] = useState5(() => String(value ?? defaultValue ?? "").length);
1120
+ const ariaNameProps = resolveAccessibleName({
1121
+ label: typeof label === "string" ? label : void 0,
1122
+ ariaLabel: props["aria-label"],
1123
+ ariaLabelledby: props["aria-labelledby"],
1124
+ componentName: "Textarea"
1125
+ });
1126
+ const { labelProps, inputProps } = useTextField(
1127
+ {
1128
+ label: typeof label === "string" ? label : void 0,
1129
+ ...ariaNameProps,
1130
+ isDisabled: disabled,
1131
+ errorMessage: typeof errorMessage === "string" ? errorMessage : void 0,
1132
+ validationState: error ? "invalid" : void 0,
1133
+ inputElementType: "textarea",
1134
+ value,
1135
+ defaultValue
1136
+ },
1137
+ innerRef
1138
+ );
1139
+ const describedBy = [props["aria-describedby"], hintId].filter(Boolean).join(" ") || void 0;
1140
+ const handleChange = (e) => {
1141
+ setCharCount(e.target.value.length);
1142
+ onChange?.(e);
1143
+ };
1144
+ const [liveValue, setLiveValue] = useState5(String(value ?? defaultValue ?? ""));
1145
+ useEffect4(() => {
1146
+ if (value != null) setLiveValue(String(value));
1147
+ }, [value]);
1148
+ const handleChangeWithMirror = (e) => {
1149
+ setLiveValue(e.target.value);
1150
+ handleChange(e);
1151
+ };
1152
+ const setLiveAndCommit = (next) => {
1153
+ setLiveValue(next);
1154
+ if (innerRef.current) innerRef.current.value = next;
1155
+ onChange?.({
1156
+ target: innerRef.current,
1157
+ currentTarget: innerRef.current
1158
+ });
1159
+ setCharCount(next.length);
1160
+ };
1161
+ const cmdPalette = useTextareaCommands({
1162
+ textareaRef: innerRef,
1163
+ value: liveValue,
1164
+ onChange: setLiveAndCommit,
1165
+ commands: commands ?? [],
1166
+ trigger: commandTrigger
1167
+ });
1168
+ const cmdEnabled = (commands?.length ?? 0) > 0;
1169
+ const sel = useTextareaSelection({
1170
+ textareaRef: innerRef,
1171
+ value: liveValue,
1172
+ onChange: setLiveAndCommit
1173
+ });
1174
+ const toolbar = useTextareaTools({
1175
+ textareaRef: innerRef,
1176
+ value: liveValue,
1177
+ onChange: setLiveAndCommit,
1178
+ tools: tools ?? []
1179
+ });
1180
+ const toolbarEnabled = (tools?.length ?? 0) > 0;
1181
+ const handleKeyDownWithCommands = (e) => {
1182
+ if (cmdEnabled) {
1183
+ const consumed = cmdPalette.onKeyDown(e);
1184
+ if (consumed) return;
1185
+ }
1186
+ props.onKeyDown?.(e);
1187
+ };
1188
+ useEffect4(() => {
1189
+ if (!autoResize) return;
1190
+ const el = innerRef.current;
1191
+ if (!el) return;
1192
+ const computed = window.getComputedStyle(el);
1193
+ const fontSize = parseFloat(computed.fontSize) || 16;
1194
+ const lhRaw = computed.lineHeight;
1195
+ const lh = lhRaw === "normal" ? fontSize * 1.2 : lhRaw.endsWith("px") ? parseFloat(lhRaw) : parseFloat(lhRaw) * fontSize;
1196
+ const padding = parseFloat(computed.paddingTop) + parseFloat(computed.paddingBottom);
1197
+ const rowCap = maxRows != null && Number.isFinite(maxRows) ? lh * maxRows + padding : Number.POSITIVE_INFINITY;
1198
+ const pixelCap = typeof maxHeight === "number" ? maxHeight : Number.POSITIVE_INFINITY;
1199
+ const effectiveMax = Math.min(rowCap, pixelCap);
1200
+ const rowFloor = lh * (minRows ?? rows) + padding;
1201
+ el.style.height = "auto";
1202
+ const target = Math.max(rowFloor, Math.min(effectiveMax, el.scrollHeight));
1203
+ el.style.height = `${target}px`;
1204
+ el.style.overflowY = el.scrollHeight > effectiveMax ? "auto" : "hidden";
1205
+ }, [autoResize, value, defaultValue, minRows, maxRows, maxHeight, rows]);
1206
+ const resolvedResize = typeof resize === "boolean" ? resize ? "vertical" : "none" : resize;
1207
+ const toCss = (v) => v == null ? void 0 : typeof v === "number" ? `${v}px` : v;
1208
+ const fieldStyle = {
1209
+ maxHeight: toCss(maxHeight),
1210
+ maxWidth: toCss(maxWidth),
1211
+ minHeight: toCss(minHeight),
1212
+ minWidth: toCss(minWidth),
1213
+ resize: resolvedResize
1214
+ };
1215
+ return /* @__PURE__ */ jsxs4(
1216
+ "div",
1217
+ {
1218
+ className: cn(
1219
+ "ods-textarea",
1220
+ `ods-textarea--${size}`,
1221
+ `ods-textarea--resize-${resolvedResize}`,
1222
+ autoResize && "ods-textarea--auto-resize",
1223
+ error && "ods-textarea--error",
1224
+ disabled && "ods-textarea--disabled",
1225
+ className
1226
+ ),
1227
+ style: consumerStyle,
1228
+ children: [
1229
+ label && /* @__PURE__ */ jsx5("label", { ...labelProps, htmlFor: baseId, className: "ods-textarea__label", children: label }),
1230
+ toolbarEnabled && toolbarPosition === "top" && /* @__PURE__ */ jsx5(TextareaToolbar, { tools: toolbar.tools, onRun: toolbar.runTool }),
1231
+ /* @__PURE__ */ jsxs4("div", { className: "ods-textarea__wrapper", children: [
1232
+ /* @__PURE__ */ jsx5(
1233
+ "textarea",
1234
+ {
1235
+ ...props,
1236
+ ...inputProps,
1237
+ ref: setRef,
1238
+ id: baseId,
1239
+ rows: autoResize ? minRows ?? rows : rows,
1240
+ disabled,
1241
+ maxLength,
1242
+ defaultValue,
1243
+ value,
1244
+ onChange: handleChangeWithMirror,
1245
+ onKeyDown: handleKeyDownWithCommands,
1246
+ className: "ods-textarea__field",
1247
+ style: fieldStyle,
1248
+ "aria-invalid": error || void 0,
1249
+ "aria-describedby": describedBy,
1250
+ "aria-autocomplete": cmdEnabled ? "list" : void 0,
1251
+ "aria-expanded": cmdEnabled ? cmdPalette.isOpen : void 0,
1252
+ "aria-controls": cmdEnabled && cmdPalette.isOpen ? `${baseId}-cmd-list` : void 0,
1253
+ "aria-activedescendant": cmdEnabled && cmdPalette.isOpen && cmdPalette.items[cmdPalette.activeIndex] ? `${baseId}-cmd-${cmdPalette.items[cmdPalette.activeIndex].id}` : void 0
1254
+ }
1255
+ ),
1256
+ cmdEnabled && cmdPalette.isOpen && cmdPalette.items.length > 0 && typeof document !== "undefined" && createPortal(
1257
+ /* @__PURE__ */ jsx5(
1258
+ "ul",
1259
+ {
1260
+ id: `${baseId}-cmd-list`,
1261
+ role: "listbox",
1262
+ "aria-label": "Inline commands",
1263
+ className: "ods-textarea__cmd-popover",
1264
+ style: {
1265
+ position: "fixed",
1266
+ top: (cmdPalette.caretRect?.bottom ?? 0) + 6,
1267
+ left: cmdPalette.caretRect?.left ?? 0
1268
+ },
1269
+ children: cmdPalette.items.map((c, i) => /* @__PURE__ */ jsxs4(
1270
+ "li",
1271
+ {
1272
+ id: `${baseId}-cmd-${c.id}`,
1273
+ role: "option",
1274
+ "aria-selected": i === cmdPalette.activeIndex,
1275
+ className: cn(
1276
+ "ods-textarea__cmd-item",
1277
+ i === cmdPalette.activeIndex && "ods-textarea__cmd-item--active"
1278
+ ),
1279
+ onMouseDown: (e) => {
1280
+ e.preventDefault();
1281
+ cmdPalette.commit(c);
1282
+ },
1283
+ onMouseEnter: () => {
1284
+ },
1285
+ children: [
1286
+ c.icon && /* @__PURE__ */ jsx5("span", { className: "ods-textarea__cmd-icon", children: c.icon }),
1287
+ /* @__PURE__ */ jsxs4("span", { className: "ods-textarea__cmd-text", children: [
1288
+ /* @__PURE__ */ jsx5("span", { className: "ods-textarea__cmd-label", children: c.label }),
1289
+ c.description && /* @__PURE__ */ jsx5("span", { className: "ods-textarea__cmd-desc", children: c.description })
1290
+ ] })
1291
+ ]
1292
+ },
1293
+ c.id
1294
+ ))
1295
+ }
1296
+ ),
1297
+ document.body
1298
+ ),
1299
+ selectionToolbar && sel.active && sel.rect && typeof document !== "undefined" && createPortal(
1300
+ /* @__PURE__ */ jsxs4(
1301
+ "div",
1302
+ {
1303
+ role: "toolbar",
1304
+ "aria-label": "Selection actions",
1305
+ className: "ods-textarea__sel-toolbar",
1306
+ style: {
1307
+ position: "fixed",
1308
+ top: sel.rect.top - 36,
1309
+ left: sel.rect.left
1310
+ },
1311
+ onMouseDown: (e) => e.preventDefault(),
1312
+ children: [
1313
+ /* @__PURE__ */ jsx5(
1314
+ "button",
1315
+ {
1316
+ type: "button",
1317
+ className: "ods-textarea__sel-btn",
1318
+ onClick: () => sel.copy(),
1319
+ "aria-label": "Copy selection",
1320
+ title: "Copy",
1321
+ children: /* @__PURE__ */ jsx5(CopyIcon, { size: "xs" })
1322
+ }
1323
+ ),
1324
+ /* @__PURE__ */ jsx5(
1325
+ "button",
1326
+ {
1327
+ type: "button",
1328
+ className: "ods-textarea__sel-btn",
1329
+ onClick: () => sel.cut(),
1330
+ "aria-label": "Cut selection",
1331
+ title: "Cut",
1332
+ children: /* @__PURE__ */ jsx5(CutIcon, { size: "xs" })
1333
+ }
1334
+ ),
1335
+ selectionActions?.map((a) => /* @__PURE__ */ jsxs4(
1336
+ "button",
1337
+ {
1338
+ type: "button",
1339
+ className: "ods-textarea__sel-btn",
1340
+ onClick: () => a.onAction(sel.text, {
1341
+ replace: sel.replace,
1342
+ wrap: sel.wrap,
1343
+ copy: sel.copy,
1344
+ cut: sel.cut
1345
+ }),
1346
+ title: typeof a.label === "string" ? a.label : void 0,
1347
+ children: [
1348
+ a.icon,
1349
+ a.label && /* @__PURE__ */ jsx5("span", { className: "ods-textarea__sel-btn-label", children: a.label })
1350
+ ]
1351
+ },
1352
+ a.id
1353
+ ))
1354
+ ]
1355
+ }
1356
+ ),
1357
+ document.body
1358
+ ),
1359
+ maxLength != null && /* @__PURE__ */ jsxs4(
1360
+ "span",
1361
+ {
1362
+ className: "ods-textarea__count",
1363
+ "aria-live": charCount > maxLength ? "polite" : "off",
1364
+ children: [
1365
+ charCount,
1366
+ "/",
1367
+ maxLength
1368
+ ]
1369
+ }
1370
+ )
1371
+ ] }),
1372
+ toolbarEnabled && toolbarPosition === "bottom" && /* @__PURE__ */ jsx5(TextareaToolbar, { tools: toolbar.tools, onRun: toolbar.runTool }),
1373
+ error && errorMessage ? /* @__PURE__ */ jsx5("div", { id: hintId, className: "ods-textarea__error-message", role: "alert", children: errorMessage }) : helperText ? /* @__PURE__ */ jsx5("div", { id: hintId, className: "ods-textarea__hint", children: helperText }) : null
1374
+ ]
1375
+ }
1376
+ );
1377
+ });
1378
+ Textarea.displayName = "Textarea";
1379
+ function TextareaToolbar({
1380
+ tools,
1381
+ onRun
1382
+ }) {
1383
+ return /* @__PURE__ */ jsx5(
1384
+ "div",
1385
+ {
1386
+ role: "toolbar",
1387
+ "aria-label": "Formatting",
1388
+ className: "ods-textarea__toolbar",
1389
+ onMouseDown: (e) => {
1390
+ if (e.target.closest(".ods-textarea__toolbar-btn")) {
1391
+ e.preventDefault();
1392
+ }
1393
+ },
1394
+ children: tools.map((t) => {
1395
+ if (t.kind === "divider") {
1396
+ return /* @__PURE__ */ jsx5("span", { className: "ods-textarea__toolbar-divider", "aria-hidden": "true" }, t.id);
1397
+ }
1398
+ return /* @__PURE__ */ jsx5(
1399
+ "button",
1400
+ {
1401
+ type: "button",
1402
+ className: "ods-textarea__toolbar-btn",
1403
+ title: t.title ?? (typeof t.label === "string" ? t.label : void 0),
1404
+ "aria-label": typeof t.label === "string" ? t.label : t.id,
1405
+ onClick: () => onRun(t.id),
1406
+ children: t.icon ? /* @__PURE__ */ jsx5("span", { className: "ods-textarea__toolbar-icon", children: t.icon }) : /* @__PURE__ */ jsx5("span", { className: "ods-textarea__toolbar-text", children: t.label })
1407
+ },
1408
+ t.id
1409
+ );
1410
+ })
1411
+ }
1412
+ );
1413
+ }
1414
+
1415
+ // src/components/TestimonialCard/TestimonialCard.tsx
1416
+ import { QuotesIcon as QuotesIcon2, StarFilledIcon, StarIcon } from "@octaviaflow/icons";
1417
+ import { forwardRef as forwardRef6, useId as useId3 } from "react";
1418
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1419
+ function isAuthorObject(v) {
1420
+ return typeof v === "object" && v !== null && !("type" in v) && // exclude React elements
1421
+ "name" in v;
1422
+ }
1423
+ var TestimonialCard = forwardRef6(
1424
+ function TestimonialCard2({
1425
+ quote,
1426
+ author,
1427
+ role: legacyRole,
1428
+ avatar: legacyAvatar,
1429
+ initial: legacyInitial,
1430
+ rating,
1431
+ logo,
1432
+ size = "md",
1433
+ radius = "md",
1434
+ id: providedId,
1435
+ className,
1436
+ ...rest
1437
+ }, ref) {
1438
+ const reactId = useId3();
1439
+ const baseId = providedId ?? `ods-testimonial-${reactId}`;
1440
+ const quoteId = `${baseId}-quote`;
1441
+ const authorId = `${baseId}-author`;
1442
+ const resolved = isAuthorObject(author) ? author : {
1443
+ name: author,
1444
+ role: legacyRole,
1445
+ avatar: legacyAvatar ? void 0 : {
1446
+ initials: typeof legacyInitial === "string" ? legacyInitial : typeof author === "string" ? author.charAt(0).toUpperCase() : void 0
1447
+ }
1448
+ };
1449
+ const renderAvatar = () => {
1450
+ if (!isAuthorObject(author) && legacyAvatar) {
1451
+ return /* @__PURE__ */ jsx6(
1452
+ "span",
1453
+ {
1454
+ className: "ods-testimonial__avatar ods-testimonial__avatar--legacy",
1455
+ "aria-hidden": "true",
1456
+ children: legacyAvatar
1457
+ }
1458
+ );
1459
+ }
1460
+ return /* @__PURE__ */ jsx6(
1461
+ Avatar,
1462
+ {
1463
+ size: size === "sm" ? "xs" : size === "lg" ? "md" : "sm",
1464
+ src: resolved.avatar?.src,
1465
+ initials: resolved.avatar?.initials,
1466
+ seed: resolved.avatar?.seed,
1467
+ palette: resolved.avatar?.palette,
1468
+ alt: resolved.avatar?.alt ?? (typeof resolved.name === "string" ? resolved.name : void 0),
1469
+ className: "ods-testimonial__avatar"
1470
+ }
1471
+ );
1472
+ };
1473
+ return /* @__PURE__ */ jsxs5(
1474
+ Card,
1475
+ {
1476
+ ...rest,
1477
+ ref,
1478
+ id: baseId,
1479
+ radius,
1480
+ padding: "none",
1481
+ variant: "subtle",
1482
+ className: cn("ods-testimonial", `ods-testimonial--${size}`, className),
1483
+ "aria-labelledby": authorId,
1484
+ "aria-describedby": quoteId,
1485
+ children: [
1486
+ /* @__PURE__ */ jsxs5("div", { className: "ods-testimonial__head", children: [
1487
+ /* @__PURE__ */ jsx6("span", { className: "ods-testimonial__quote", "aria-hidden": "true", children: /* @__PURE__ */ jsx6(QuotesIcon2, { size: "md" }) }),
1488
+ logo && /* @__PURE__ */ jsx6("span", { className: "ods-testimonial__logo", "aria-hidden": "true", children: logo })
1489
+ ] }),
1490
+ /* @__PURE__ */ jsx6("blockquote", { id: quoteId, className: "ods-testimonial__text", children: quote }),
1491
+ typeof rating === "number" && /* @__PURE__ */ jsx6(
1492
+ "div",
1493
+ {
1494
+ className: "ods-testimonial__rating",
1495
+ role: "img",
1496
+ "aria-label": `${rating} out of 5 stars`,
1497
+ children: Array.from({ length: 5 }).map(
1498
+ (_, i) => i < Math.round(rating) ? /* @__PURE__ */ jsx6(
1499
+ StarFilledIcon,
1500
+ {
1501
+ size: "xs",
1502
+ className: "ods-testimonial__star ods-testimonial__star--on"
1503
+ },
1504
+ i
1505
+ ) : /* @__PURE__ */ jsx6(StarIcon, { size: "xs", className: "ods-testimonial__star" }, i)
1506
+ )
1507
+ }
1508
+ ),
1509
+ /* @__PURE__ */ jsxs5("figcaption", { className: "ods-testimonial__author", id: authorId, children: [
1510
+ renderAvatar(),
1511
+ /* @__PURE__ */ jsxs5("span", { className: "ods-testimonial__author-info", children: [
1512
+ /* @__PURE__ */ jsx6("span", { className: "ods-testimonial__author-name", children: resolved.name }),
1513
+ resolved.role && /* @__PURE__ */ jsx6("span", { className: "ods-testimonial__author-role", children: resolved.role })
1514
+ ] })
1515
+ ] })
1516
+ ]
1517
+ }
1518
+ );
1519
+ }
1520
+ );
1521
+ TestimonialCard.displayName = "TestimonialCard";
1522
+
1523
+ export {
1524
+ Card,
1525
+ CardHeader,
1526
+ CardBody,
1527
+ CardFooter,
1528
+ CardTitle,
1529
+ CardDescription,
1530
+ AVATAR_PALETTE_SIZE,
1531
+ avatarPaletteIndex,
1532
+ Avatar,
1533
+ AvatarStack,
1534
+ BlogCard,
1535
+ easeLinear,
1536
+ easeOutCubic,
1537
+ easeOutQuart,
1538
+ easeOutExpo,
1539
+ CountUp,
1540
+ useTextareaCommands,
1541
+ useTextareaSelection,
1542
+ useTextareaTools,
1543
+ textareaTools,
1544
+ Textarea,
1545
+ TestimonialCard
1546
+ };
1547
+ //# sourceMappingURL=chunk-ZALBYWCU.js.map