@flikk/ui 1.0.0-beta.22 → 1.0.0-beta.24

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 (161) hide show
  1. package/dist/components/ai/PromptInput/PromptInput.js +139 -7
  2. package/dist/components/ai/PromptInput/VoiceRecorder.js +84 -0
  3. package/dist/components/charts/AreaChart/AreaChart.types.d.ts +2 -2
  4. package/dist/components/charts/BarChart/BarChart.types.d.ts +2 -2
  5. package/dist/components/charts/ComboChart/ComboChart.types.d.ts +2 -2
  6. package/dist/components/charts/LineChart/LineChart.types.d.ts +2 -2
  7. package/dist/components/charts/ScatterPlot/ScatterPlot.types.d.ts +2 -2
  8. package/dist/components/charts/StackedBarChart/StackedBarChart.types.d.ts +2 -2
  9. package/dist/components/core/Accordion/AccordionTrigger.js +28 -1
  10. package/dist/components/core/Alert/Alert.js +2 -1
  11. package/dist/components/core/AlertDialog/AlertDialog.js +1 -1
  12. package/dist/components/core/Badge/Badge.js +6 -17
  13. package/dist/components/core/Breadcrumbs/Breadcrumbs.js +17 -28
  14. package/dist/components/core/Calendar/Calendar.js +1 -1
  15. package/dist/components/core/Carousel/CarouselBody.js +6 -1
  16. package/dist/components/core/ContextMenu/ContextMenuBody.js +6 -3
  17. package/dist/components/core/ContextMenu/ContextMenuSubBody.js +6 -3
  18. package/dist/components/core/DragDrop/DragDrop.js +170 -17
  19. package/dist/components/core/DragDrop/DragDrop.types.d.ts +6 -0
  20. package/dist/components/core/Drawer/Drawer.d.ts +1 -1
  21. package/dist/components/core/Drawer/Drawer.js +2 -0
  22. package/dist/components/core/Drawer/Drawer.types.d.ts +2 -0
  23. package/dist/components/core/Drawer/DrawerTitle.d.ts +1 -1
  24. package/dist/components/core/Drawer/DrawerTitle.js +2 -2
  25. package/dist/components/core/Dropdown/DropdownMenu.js +2 -30
  26. package/dist/components/core/Masonry/Masonry.js +7 -2
  27. package/dist/components/core/Modal/Modal.d.ts +1 -1
  28. package/dist/components/core/Modal/Modal.js +3 -3
  29. package/dist/components/core/Modal/Modal.types.d.ts +2 -0
  30. package/dist/components/core/Modal/ModalTitle.d.ts +1 -1
  31. package/dist/components/core/Modal/ModalTitle.js +2 -2
  32. package/dist/components/core/NavItem/NavItem.js +21 -6
  33. package/dist/components/core/NavItem/NavItem.theme.js +2 -2
  34. package/dist/components/core/Pagination/Pagination.js +1 -1
  35. package/dist/components/core/Popover/PopoverBody.js +3 -27
  36. package/dist/components/core/Popover/PopoverTrigger.js +1 -1
  37. package/dist/components/core/Progress/Progress.js +4 -4
  38. package/dist/components/core/Rating/Rating.js +1 -1
  39. package/dist/components/core/ScrollArea/ScrollArea.js +3 -2
  40. package/dist/components/core/Segmented/Segmented.js +6 -6
  41. package/dist/components/core/Segmented/SegmentedItem.js +28 -2
  42. package/dist/components/core/Sidebar/Sidebar.d.ts +1 -0
  43. package/dist/components/core/Sidebar/Sidebar.js +5 -3
  44. package/dist/components/core/Sidebar/Sidebar.types.d.ts +7 -1
  45. package/dist/components/core/Sidebar/SidebarContent.js +1 -1
  46. package/dist/components/core/Sidebar/SidebarFooter.js +1 -1
  47. package/dist/components/core/Sidebar/SidebarHeader.js +5 -2
  48. package/dist/components/core/Sidebar/SidebarLogo.d.ts +3 -0
  49. package/dist/components/core/Sidebar/SidebarLogo.js +17 -0
  50. package/dist/components/core/Sidebar/SidebarNavGroup.js +2 -1
  51. package/dist/components/core/Sidebar/SidebarToggle.js +2 -4
  52. package/dist/components/core/Sidebar/SidebarUserProfile.js +3 -6
  53. package/dist/components/core/Sidebar/index.d.ts +2 -1
  54. package/dist/components/core/Skeleton/Skeleton.js +2 -2
  55. package/dist/components/core/Sortable/Sortable.d.ts +1 -1
  56. package/dist/components/core/Sortable/Sortable.js +20 -4
  57. package/dist/components/core/Sortable/Sortable.types.d.ts +2 -0
  58. package/dist/components/core/Tabs/Tabs.js +6 -4
  59. package/dist/components/core/Tabs/Tabs.types.d.ts +2 -0
  60. package/dist/components/core/Tabs/TabsBody.js +3 -3
  61. package/dist/components/core/Tabs/TabsList.js +19 -21
  62. package/dist/components/core/Tabs/TabsTrigger.js +47 -28
  63. package/dist/components/core/Toast/Toast.js +1 -1
  64. package/dist/components/core/Toast/ToastProvider.js +3 -2
  65. package/dist/components/core/Tooltip/Tooltip.d.ts +1 -1
  66. package/dist/components/core/Tooltip/Tooltip.js +26 -35
  67. package/dist/components/core/Tooltip/Tooltip.types.d.ts +5 -1
  68. package/dist/components/core/Tree/Tree.js +178 -8
  69. package/dist/components/core/index.js +1 -0
  70. package/dist/components/data-display/GanttChart/GanttSplitter.js +15 -1
  71. package/dist/components/data-display/Table/Table.js +2 -2
  72. package/dist/components/data-display/Table/Table.types.d.ts +2 -0
  73. package/dist/components/data-display/Table/TableFilter.js +21 -18
  74. package/dist/components/effects/CustomCursor/CustomCursor.js +3 -7
  75. package/dist/components/effects/Overlay/Overlay.js +4 -9
  76. package/dist/components/effects/PageTransition/PageTransition.js +17 -6
  77. package/dist/components/effects/SpotlightBorder/SpotlightBorder.js +3 -4
  78. package/dist/components/forms/Checkbox/Checkbox.js +11 -1
  79. package/dist/components/forms/Checkbox/Checkbox.theme.js +4 -1
  80. package/dist/components/forms/Checkbox/Checkbox.types.d.ts +7 -5
  81. package/dist/components/forms/Checkbox/CheckboxGroup.js +9 -4
  82. package/dist/components/forms/ColorPicker/ColorPicker.js +7 -4
  83. package/dist/components/forms/ColorPicker/ColorPicker.types.d.ts +2 -2
  84. package/dist/components/forms/ColorPicker/ColorPickerBody.js +5 -3
  85. package/dist/components/forms/ColorPicker/ColorPickerEyeDropper.js +3 -3
  86. package/dist/components/forms/ColorPicker/ColorPickerGradient.js +8 -8
  87. package/dist/components/forms/ColorPicker/ColorPickerInput.js +1 -1
  88. package/dist/components/forms/ColorPicker/index.d.ts +1 -1
  89. package/dist/components/forms/Combobox/Combobox.js +20 -45
  90. package/dist/components/forms/Combobox/Combobox.types.d.ts +4 -2
  91. package/dist/components/forms/CronInput/CronInput.js +10 -4
  92. package/dist/components/forms/CronInput/CronInput.types.d.ts +12 -1
  93. package/dist/components/forms/DatePicker/DatePicker.js +2 -2
  94. package/dist/components/forms/DatePicker/DatePicker.types.d.ts +4 -2
  95. package/dist/components/forms/DatePicker/DatePickerBody.js +1 -29
  96. package/dist/components/forms/DatePicker/DatePickerTrigger.js +2 -2
  97. package/dist/components/forms/DateRangePicker/DateRangePicker.js +3 -3
  98. package/dist/components/forms/DateRangePicker/DateRangePicker.types.d.ts +4 -2
  99. package/dist/components/forms/DateRangePicker/DateRangePickerBody.js +1 -28
  100. package/dist/components/forms/DateRangePicker/DateRangePickerTrigger.js +2 -2
  101. package/dist/components/forms/FileUpload/FileUpload.js +99 -10
  102. package/dist/components/forms/FileUpload/FileUpload.types.d.ts +15 -0
  103. package/dist/components/forms/FormLabel/FormLabel.js +2 -2
  104. package/dist/components/forms/Input/Input.js +5 -3
  105. package/dist/components/forms/Input/Input.types.d.ts +2 -0
  106. package/dist/components/forms/InputAddress/InputAddress.d.ts +1 -1
  107. package/dist/components/forms/InputAddress/InputAddress.js +8 -9
  108. package/dist/components/forms/InputCounter/InputCounter.js +25 -18
  109. package/dist/components/forms/InputCounter/InputCounter.types.d.ts +8 -1
  110. package/dist/components/forms/InputCreditCard/InputCreditCard.d.ts +1 -1
  111. package/dist/components/forms/InputCreditCard/InputCreditCard.js +27 -9
  112. package/dist/components/forms/InputCreditCard/InputCreditCard.types.d.ts +5 -0
  113. package/dist/components/forms/InputOTP/InputOTP.js +26 -17
  114. package/dist/components/forms/InputOTP/InputOTP.types.d.ts +21 -4
  115. package/dist/components/forms/InputTag/InputTag.js +12 -39
  116. package/dist/components/forms/InputTag/InputTag.types.d.ts +2 -2
  117. package/dist/components/forms/Mention/Mention.js +13 -6
  118. package/dist/components/forms/Mention/Mention.types.d.ts +9 -0
  119. package/dist/components/forms/Radio/Radio.js +12 -2
  120. package/dist/components/forms/Radio/Radio.theme.js +5 -1
  121. package/dist/components/forms/Radio/Radio.types.d.ts +7 -5
  122. package/dist/components/forms/Radio/RadioGroup.js +8 -3
  123. package/dist/components/forms/RichTextEditor/RichTextEditor.js +21 -21
  124. package/dist/components/forms/RichTextEditor/RichTextEditor.types.d.ts +2 -2
  125. package/dist/components/forms/Select/Select.d.ts +2 -0
  126. package/dist/components/forms/Select/Select.js +26 -56
  127. package/dist/components/forms/Select/Select.types.d.ts +14 -0
  128. package/dist/components/forms/Signature/Signature.js +1 -1
  129. package/dist/components/forms/Signature/Signature.types.d.ts +3 -3
  130. package/dist/components/forms/Slider/Slider.js +18 -4
  131. package/dist/components/forms/Slider/Slider.types.d.ts +2 -2
  132. package/dist/components/forms/Switch/Switch.js +12 -19
  133. package/dist/components/forms/Switch/Switch.theme.js +12 -2
  134. package/dist/components/forms/Switch/Switch.types.d.ts +20 -2
  135. package/dist/components/forms/Textarea/Textarea.js +8 -3
  136. package/dist/components/forms/Textarea/Textarea.types.d.ts +2 -0
  137. package/dist/components/forms/TimePicker/TimePicker.js +1 -1
  138. package/dist/components/forms/TimePicker/TimePicker.types.d.ts +6 -2
  139. package/dist/components/forms/TimePicker/TimePickerContent.js +88 -30
  140. package/dist/components/forms/TimePicker/TimePickerTrigger.js +2 -2
  141. package/dist/components/forms/index.js +86 -1
  142. package/dist/components/layout/FormLayout/FormLayout.js +87 -1
  143. package/dist/components/layout/index.js +4 -0
  144. package/dist/hooks/index.d.ts +1 -0
  145. package/dist/hooks/useClickOutside.d.ts +10 -4
  146. package/dist/hooks/useClickOutside.js +44 -24
  147. package/dist/hooks/useDarkMode.d.ts +1 -0
  148. package/dist/hooks/useDarkMode.js +42 -0
  149. package/dist/hooks/useFormStateMachine.d.ts +1 -1
  150. package/dist/hooks/useNetworkStatus.js +1 -1
  151. package/dist/hooks/useOverlay.js +4 -0
  152. package/dist/hooks/useScaleBackground.js +5 -2
  153. package/dist/hooks/useSelectPortal.js +14 -5
  154. package/dist/index.d.ts +0 -2
  155. package/dist/index.js +174 -223
  156. package/dist/shadcn-compat.css +80 -0
  157. package/dist/styles.css +1 -1
  158. package/dist/utils/stateMachine.d.ts +4 -4
  159. package/package.json +12 -10
  160. package/tailwind.preset.cjs +32 -3
  161. /package/{src/theme-plugin.css → dist/theme.css} +0 -0
@@ -1,4 +1,4 @@
1
- import { jsxs, jsx } from 'react/jsx-runtime';
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import React__default, { useMemo, useState, useRef, useEffect, useCallback } from 'react';
3
3
  import { AnimatePresence, motion } from 'motion/react';
4
4
  import { createPortal } from 'react-dom';
@@ -11,35 +11,8 @@ import { inputTagTheme } from './InputTag.theme.js';
11
11
  import { useSelectPortal } from '../../../hooks/useSelectPortal.js';
12
12
  import { createDropdownAnimations } from '../Select/Select.animations.js';
13
13
  import { useIsClient } from '../../../hooks/useIsClient.js';
14
+ import { useDarkMode } from '../../../hooks/useDarkMode.js';
14
15
 
15
- /**
16
- * Hook to detect dark mode state from document
17
- */
18
- const useDarkMode = () => {
19
- const [isDark, setIsDark] = useState(false);
20
- useEffect(() => {
21
- if (typeof document === "undefined")
22
- return;
23
- const checkDarkMode = () => {
24
- const hasDarkClass = document.documentElement.classList.contains("dark") ||
25
- document.body.classList.contains("dark") ||
26
- document.querySelector(".dark") !== null;
27
- setIsDark(hasDarkClass);
28
- };
29
- checkDarkMode();
30
- const observer = new MutationObserver(checkDarkMode);
31
- observer.observe(document.documentElement, {
32
- attributes: true,
33
- attributeFilter: ["class"],
34
- });
35
- observer.observe(document.body, {
36
- attributes: true,
37
- attributeFilter: ["class"],
38
- });
39
- return () => observer.disconnect();
40
- }, []);
41
- return isDark;
42
- };
43
16
  /**
44
17
  * Default filter function for suggestions
45
18
  */
@@ -97,16 +70,16 @@ const InputTagOptions = ({ isOpen, onClose, triggerRef, filteredOptions, selecte
97
70
  width: `${position.width}px`,
98
71
  }
99
72
  : {}),
100
- }, tabIndex: -1, variants: animations, initial: "initial", animate: "visible", exit: "exit", children: filteredOptions.length === 0 ? (jsx("div", { className: theme.emptyMessageStyle, children: emptyMessage })) : (filteredOptions.map((option, index) => {
101
- const isSelected = selectedTags.includes(option.value);
102
- const isHighlighted = index === highlightedIndex;
103
- const isCreateOption = option.id === "__create__";
104
- return (jsx("div", { role: "option", "aria-selected": isSelected, "aria-disabled": option.disabled, "data-option-index": index, className: cn(theme.optionStyle, isHighlighted && theme.highlightedOptionStyle, option.disabled && theme.disabledOptionStyle, isCreateOption && theme.createOptionStyle), onMouseEnter: () => !option.disabled && setHighlightedIndex(index), onClick: () => {
105
- if (!option.disabled) {
106
- onSelectOption(option, isCreateOption);
107
- }
108
- }, children: isCreateOption ? (jsxs("span", { className: "flex items-center gap-1", children: [jsx(PlusIcon, { className: "size-4 shrink-0", strokeWidth: 2 }), jsx("span", { className: "block truncate", children: option.label })] })) : (jsxs("span", { className: "flex items-center justify-between gap-2", children: [jsx("span", { className: "block truncate", children: option.label }), showSelectedIndicator && isSelected && (jsx(CheckIcon, { className: "size-4 shrink-0 text-[var(--color-primary)]", strokeWidth: 2 }))] })) }, option.id));
109
- })) })) }));
73
+ }, tabIndex: -1, variants: animations, initial: "initial", animate: "visible", exit: "exit", children: filteredOptions.length === 0 ? (jsx("div", { className: theme.emptyMessageStyle, children: emptyMessage })) : (jsxs(Fragment, { children: [(filteredOptions.length > 100 ? filteredOptions.slice(0, 100) : filteredOptions).map((option, index) => {
74
+ const isSelected = selectedTags.includes(option.value);
75
+ const isHighlighted = index === highlightedIndex;
76
+ const isCreateOption = option.id === "__create__";
77
+ return (jsx("div", { role: "option", "aria-selected": isSelected, "aria-disabled": option.disabled, "data-option-index": index, className: cn(theme.optionStyle, isHighlighted && theme.highlightedOptionStyle, option.disabled && theme.disabledOptionStyle, isCreateOption && theme.createOptionStyle), onMouseEnter: () => !option.disabled && setHighlightedIndex(index), onClick: () => {
78
+ if (!option.disabled) {
79
+ onSelectOption(option, isCreateOption);
80
+ }
81
+ }, children: isCreateOption ? (jsxs("span", { className: "flex items-center gap-1", children: [jsx(PlusIcon, { className: "size-4 shrink-0", strokeWidth: 2 }), jsx("span", { className: "block truncate", children: option.label })] })) : (jsxs("span", { className: "flex items-center justify-between gap-2", children: [jsx("span", { className: "block truncate", children: option.label }), showSelectedIndicator && isSelected && (jsx(CheckIcon, { className: "size-4 shrink-0 text-[var(--color-primary)]", strokeWidth: 2 }))] })) }, option.id));
82
+ }), filteredOptions.length > 100 && (jsxs("div", { className: "px-3 py-2 text-xs text-[var(--color-text-muted)] text-center border-t border-[var(--color-border)]", children: ["Showing 100 of ", filteredOptions.length, " results \u2014 refine your search"] }))] })) })) }));
110
83
  if (portal && isClient) {
111
84
  return createPortal(jsx("div", { className: isDarkMode ? "dark" : undefined, children: optionsContent }), document.body);
112
85
  }
@@ -33,9 +33,9 @@ export interface InputTagProps extends Omit<React.HTMLAttributes<HTMLDivElement>
33
33
  /** The state of the input */
34
34
  state?: InputTagState;
35
35
  /** Label for the input */
36
- label?: string;
36
+ label?: React.ReactNode;
37
37
  /** Helper text displayed below the tags */
38
- helperText?: string;
38
+ helperText?: React.ReactNode;
39
39
  /** Placeholder text for the input */
40
40
  placeholder?: string;
41
41
  /** Whether the input is disabled */
@@ -1,11 +1,12 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import React__default, { useMemo, useState, useRef, useEffect, useCallback, useLayoutEffect } from 'react';
2
+ import React__default, { useMemo, useId, useState, useRef, useEffect, useCallback, useLayoutEffect } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
4
  import { AnimatePresence, motion } from 'motion/react';
5
5
  import { mentionTheme } from './Mention.theme.js';
6
6
  import { cn } from '../../../utils/cn.js';
7
7
  import { Avatar } from '../../core/Avatar/Avatar.js';
8
8
  import { Tag } from '../../core/Tag/Tag.js';
9
+ import { FormLabel } from '../FormLabel/FormLabel.js';
9
10
  import { useIsClient } from '../../../hooks/useIsClient.js';
10
11
  import { normalizeSegments, setCaretAtOffset, getPlainTextOffset, parseDOMToSegments, serializeSegments, serializeSegmentsMasked, insertMentionIntoSegments, MENTION_ATTR } from './Mention.utils.js';
11
12
 
@@ -73,8 +74,11 @@ const dropdownVariants = {
73
74
  // ---------------------------------------------------------------------------
74
75
  // Mention component
75
76
  // ---------------------------------------------------------------------------
76
- const Mention = React__default.forwardRef(({ triggers: triggersProp, suggestions: suggestionsProp, onSearch: onSearchProp, value: controlledValue, defaultValue = "", onChange, onMentionSelect, onMentionsChange, placeholder, size = "md", maxSuggestions = 8, className, wrapperClassName, dropdownClassName, theme: themeOverrides, disabled = false, renderSuggestion, emptyMessage = "No results found", loading = false, mentionTagSize = "sm", mentionTagClassName, rows = 3, ...props }, ref) => {
77
+ const Mention = React__default.forwardRef(({ triggers: triggersProp, suggestions: suggestionsProp, onSearch: onSearchProp, value: controlledValue, defaultValue = "", onChange, onMentionSelect, onMentionsChange, placeholder, size = "md", maxSuggestions = 8, className, wrapperClassName, dropdownClassName, theme: themeOverrides, state = "default", disabled = false, helperText, required, label, renderSuggestion, emptyMessage = "No results found", loading = false, mentionTagSize = "sm", mentionTagClassName, rows = 3, ...props }, ref) => {
77
78
  const theme = useMemo(() => ({ ...mentionTheme, ...(themeOverrides || {}) }), [themeOverrides]);
79
+ const generatedId = useId();
80
+ const isDisabled = state === "disabled" || disabled;
81
+ const isInvalid = state === "invalid";
78
82
  const triggers = useMemo(() => {
79
83
  if (triggersProp && triggersProp.length > 0)
80
84
  return triggersProp;
@@ -150,7 +154,7 @@ const Mention = React__default.forwardRef(({ triggers: triggersProp, suggestions
150
154
  if (!activeMention || !(activeTriggerConfig === null || activeTriggerConfig === void 0 ? void 0 : activeTriggerConfig.onSearch))
151
155
  return;
152
156
  activeTriggerConfig.onSearch(activeMention.query);
153
- }, [activeMention === null || activeMention === void 0 ? void 0 : activeMention.query, activeMention === null || activeMention === void 0 ? void 0 : activeMention.trigger]); // eslint-disable-line react-hooks/exhaustive-deps
157
+ }, [activeMention === null || activeMention === void 0 ? void 0 : activeMention.query, activeMention === null || activeMention === void 0 ? void 0 : activeMention.trigger, activeTriggerConfig]);
154
158
  // Reset highlighted index when suggestions change
155
159
  useEffect(() => {
156
160
  setHighlightedIndex(filteredSuggestions.length > 0 ? 0 : -1);
@@ -596,11 +600,14 @@ const Mention = React__default.forwardRef(({ triggers: triggersProp, suggestions
596
600
  // -----------------------------------------------------------------------
597
601
  // Render
598
602
  // -----------------------------------------------------------------------
599
- return (jsxs("div", { className: cn(theme.wrapperStyle, wrapperClassName), children: [jsx("div", { ref: wrapperRef, className: cn(theme.inputGroupStyle, isFocused && theme.inputGroupFocusStyle), children: jsx("div", { ref: setEditableRef, contentEditable: !disabled, suppressContentEditableWarning: true, onInput: handleInput, onKeyDown: handleKeyDown, onClick: handleClick, onFocus: handleFocus, onBlur: handleBlur, onPaste: handlePaste, onSelect: handleSelect, onCompositionStart: handleCompositionStart, onCompositionEnd: handleCompositionEnd, role: "textbox", "aria-multiline": "true", "aria-autocomplete": "list", "aria-expanded": isDropdownOpen, "aria-haspopup": "listbox", "aria-placeholder": placeholder, "data-placeholder": placeholder, "aria-disabled": disabled || undefined, className: cn(theme.editableStyle, theme.sizes[size], isContentEmpty &&
600
- "before:content-[attr(data-placeholder)] before:text-[var(--color-text-placeholder)] before:pointer-events-none before:absolute dark:before:text-[var(--color-neutral-500)]", disabled && "cursor-not-allowed opacity-60", className), style: {
603
+ const helperId = `${generatedId}-helper`;
604
+ return (jsxs("div", { className: cn(theme.wrapperStyle, wrapperClassName), children: [label && (jsx(FormLabel, { htmlFor: generatedId, state: isDisabled ? "disabled" : isInvalid ? "invalid" : "default", required: required, className: "mb-1.5", children: label })), jsx("div", { ref: wrapperRef, className: cn(theme.inputGroupStyle, isFocused && theme.inputGroupFocusStyle, isInvalid && "border-[var(--color-danger)] ring-1 ring-[var(--color-danger)]"), children: jsx("div", { ref: setEditableRef, id: generatedId, contentEditable: !isDisabled, suppressContentEditableWarning: true, onInput: handleInput, onKeyDown: handleKeyDown, onClick: handleClick, onFocus: handleFocus, onBlur: handleBlur, onPaste: handlePaste, onSelect: handleSelect, onCompositionStart: handleCompositionStart, onCompositionEnd: handleCompositionEnd, role: "textbox", "aria-multiline": "true", "aria-autocomplete": "list", "aria-expanded": isDropdownOpen, "aria-haspopup": "listbox", "aria-placeholder": placeholder, "aria-required": required || undefined, "data-placeholder": placeholder, "aria-disabled": isDisabled || undefined, "aria-invalid": isInvalid || undefined, "aria-describedby": helperText ? helperId : undefined, className: cn(theme.editableStyle, theme.sizes[size], isContentEmpty &&
605
+ "before:content-[attr(data-placeholder)] before:text-[var(--color-text-placeholder)] before:pointer-events-none before:absolute dark:before:text-[var(--color-neutral-500)]", isDisabled && "cursor-not-allowed opacity-60", className), style: {
601
606
  minHeight: rows ? `${rows * 1.5}em` : undefined,
602
607
  position: "relative",
603
- }, ...props, children: renderedSegments }) }), isClient && createPortal(dropdownContent, document.body)] }));
608
+ }, ...props, children: renderedSegments }) }), helperText && (jsx("div", { id: helperId, className: cn("text-sm mt-1", isInvalid
609
+ ? "text-[var(--color-danger)]"
610
+ : "text-[var(--color-text-muted)]"), children: helperText })), isClient && createPortal(dropdownContent, document.body)] }));
604
611
  });
605
612
  Mention.displayName = "Mention";
606
613
 
@@ -100,6 +100,7 @@ export interface MentionTheme {
100
100
  * Partial theme overrides for the Mention component.
101
101
  */
102
102
  export type MentionThemeOverrides = Partial<MentionTheme>;
103
+ export type MentionState = "default" | "disabled" | "invalid";
103
104
  /**
104
105
  * Props for the Mention component.
105
106
  */
@@ -134,8 +135,14 @@ export interface MentionProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
134
135
  dropdownClassName?: string;
135
136
  /** Theme overrides */
136
137
  theme?: MentionThemeOverrides;
138
+ /** Validation/interaction state */
139
+ state?: MentionState;
137
140
  /** Whether the mention input is disabled */
138
141
  disabled?: boolean;
142
+ /** Helper text rendered below the mention input */
143
+ helperText?: React.ReactNode;
144
+ /** Whether the field is required */
145
+ required?: boolean;
139
146
  /** Custom renderer for suggestion items */
140
147
  renderSuggestion?: (suggestion: MentionSuggestion, isHighlighted: boolean, trigger: string) => React.ReactNode;
141
148
  /** Message shown when no suggestions match */
@@ -148,4 +155,6 @@ export interface MentionProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
148
155
  mentionTagClassName?: string;
149
156
  /** Number of visible text rows (controls min-height) */
150
157
  rows?: number;
158
+ /** Label rendered above the mention input */
159
+ label?: string;
151
160
  }
@@ -1,5 +1,5 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import React__default, { useId, useState } from 'react';
2
+ import React__default, { useId, useState, useEffect } from 'react';
3
3
  import { useReducedMotion, motion } from 'motion/react';
4
4
  import { radioTheme } from './Radio.theme.js';
5
5
  import { formLabelTheme } from '../FormLabel/FormLabel.theme.js';
@@ -22,6 +22,7 @@ const RadioComponent = React__default.forwardRef(({ id: idProp, name: nameProp,
22
22
  const size = (_c = groupContext === null || groupContext === void 0 ? void 0 : groupContext.size) !== null && _c !== void 0 ? _c : sizeProp;
23
23
  const state = stateProp === "disabled" ? "disabled" : ((_d = groupContext === null || groupContext === void 0 ? void 0 : groupContext.state) !== null && _d !== void 0 ? _d : stateProp);
24
24
  const isDisabled = state === "disabled";
25
+ const isInvalid = state === "invalid";
25
26
  // Determine checked state
26
27
  const isInGroup = groupContext !== undefined;
27
28
  const checked = isInGroup ? groupContext.value === value : checkedProp;
@@ -43,7 +44,16 @@ const RadioComponent = React__default.forwardRef(({ id: idProp, name: nameProp,
43
44
  const inputProps = isControlled
44
45
  ? { checked }
45
46
  : { defaultChecked };
46
- return (jsxs("div", { className: cn(radioTheme.baseStyle, className), ...restProps, children: [jsxs("div", { className: cn(radioTheme.inputContainerStyle, radioTheme.sizes[size]), children: [jsx("input", { ref: ref, type: "radio", id: id, name: name, value: value, ...inputProps, onChange: handleChange, disabled: isDisabled, "aria-describedby": description ? `${id}-description` : undefined, "data-state": isDisabled ? "disabled" : "default", className: cn("peer", radioTheme.inputStyle, radioTheme.sizes[size]) }), jsx(motion.div, { className: cn(radioTheme.dotStyle, radioTheme.dotSizes[size], isDisabled && "saturate-0 opacity-80"), initial: false, animate: isChecked ? "checked" : "unchecked", variants: shouldReduceMotion ? reducedMotionDotVariants : radioDotVariants })] }), (label || description) && (jsxs("label", { htmlFor: id, className: cn("cursor-pointer", isDisabled && "cursor-not-allowed"), children: [label && (typeof label === 'string' ? (jsx("span", { className: cn(formLabelTheme.baseStyle, formLabelTheme.stateStyles[state], "mb-0"), children: label })) : label), description && (typeof description === 'string' ? (jsx("div", { id: `${id}-description`, className: radioTheme.descriptionStyle, children: description })) : description)] }))] }));
47
+ // Dev-only warning when no accessible name is provided
48
+ useEffect(() => {
49
+ if (process.env.NODE_ENV !== 'production') {
50
+ if (!label && !restProps['aria-label'] && !restProps['aria-labelledby']) {
51
+ console.warn('[Radio]: No accessible name provided. Add a `label` prop, `aria-label`, or `aria-labelledby`.');
52
+ }
53
+ }
54
+ // eslint-disable-next-line react-hooks/exhaustive-deps
55
+ }, []);
56
+ return (jsxs("div", { className: cn(radioTheme.baseStyle, className), ...restProps, children: [jsxs("div", { className: cn(radioTheme.inputContainerStyle, radioTheme.sizes[size]), children: [jsx("input", { ref: ref, type: "radio", id: id, name: name, value: value, ...inputProps, onChange: handleChange, disabled: isDisabled, "aria-describedby": description ? `${id}-description` : undefined, "aria-invalid": isInvalid || undefined, "data-state": isDisabled ? "disabled" : isInvalid ? "invalid" : "default", className: cn("peer", radioTheme.inputStyle, radioTheme.sizes[size]) }), jsx(motion.div, { className: cn(radioTheme.dotStyle, radioTheme.dotSizes[size], isDisabled && "saturate-0 opacity-80"), initial: false, animate: isChecked ? "checked" : "unchecked", variants: shouldReduceMotion ? reducedMotionDotVariants : radioDotVariants })] }), (label || description) && (jsxs("label", { htmlFor: id, className: cn("cursor-pointer", isDisabled && "cursor-not-allowed"), children: [label && (typeof label === 'string' ? (jsx("span", { className: cn(formLabelTheme.baseStyle, formLabelTheme.stateStyles[state], "mb-0"), children: label })) : label), description && (typeof description === 'string' ? (jsx("div", { id: `${id}-description`, className: radioTheme.descriptionStyle, children: description })) : description)] }))] }));
47
57
  });
48
58
  RadioComponent.displayName = "Radio";
49
59
  const Radio = Object.assign(RadioComponent, { Group: RadioGroup });
@@ -23,16 +23,20 @@ const radioTheme = {
23
23
  "data-[state=disabled]:border-[var(--color-border)] data-[state=disabled]:bg-[var(--color-background-disabled)] data-[state=disabled]:cursor-not-allowed " +
24
24
  // Disabled state - dark
25
25
  "dark:disabled:bg-[var(--color-neutral-700)] dark:disabled:border-[var(--color-neutral-600)] " +
26
- "dark:data-[state=disabled]:bg-[var(--color-neutral-700)] dark:data-[state=disabled]:border-[var(--color-neutral-600)]",
26
+ "dark:data-[state=disabled]:bg-[var(--color-neutral-700)] dark:data-[state=disabled]:border-[var(--color-neutral-600)] " +
27
+ // Invalid state
28
+ "data-[state=invalid]:border-[var(--color-danger)] data-[state=invalid]:focus-visible:outline-[var(--color-danger)]",
27
29
  dotStyle: "absolute top-1/2 left-1/2 pointer-events-none rounded-full bg-[var(--color-primary)]",
28
30
  dotSizes: {
29
31
  sm: "size-2.5 mt-0.25",
30
32
  md: "size-3",
33
+ lg: "size-3.5",
31
34
  },
32
35
  descriptionStyle: "text-sm text-[var(--color-text-secondary)]/80 mt-0",
33
36
  sizes: {
34
37
  sm: "size-5 mt-0.5",
35
38
  md: "size-6",
39
+ lg: "size-7",
36
40
  },
37
41
  // Group styles
38
42
  groupStyle: "flex flex-col gap-1.5",
@@ -2,11 +2,11 @@ import React from 'react';
2
2
  /**
3
3
  * State variants for the radio component
4
4
  */
5
- export type RadioState = 'default' | 'disabled';
5
+ export type RadioState = 'default' | 'disabled' | 'invalid';
6
6
  /**
7
7
  * Size variants for the radio component
8
8
  */
9
- export type RadioSize = 'sm' | 'md';
9
+ export type RadioSize = 'sm' | 'md' | 'lg';
10
10
  /**
11
11
  * Orientation for Radio.Group layout
12
12
  */
@@ -14,11 +14,9 @@ export type RadioGroupOrientation = 'vertical' | 'horizontal';
14
14
  /**
15
15
  * Radio component props
16
16
  */
17
- export interface RadioProps extends Omit<React.HTMLAttributes<HTMLInputElement>, 'onChange' | 'size'> {
17
+ export interface RadioProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'size'> {
18
18
  id?: string;
19
- name?: string;
20
19
  value: string | number;
21
- checked?: boolean;
22
20
  onChange?: (checked: boolean, value: string | number) => void;
23
21
  label?: React.ReactNode;
24
22
  description?: React.ReactNode;
@@ -39,7 +37,11 @@ export interface RadioGroupProps extends Omit<React.HTMLAttributes<HTMLFieldSetE
39
37
  orientation?: RadioGroupOrientation;
40
38
  label?: React.ReactNode;
41
39
  description?: React.ReactNode;
40
+ /**
41
+ * @deprecated Use `state='invalid'` with `errorMessage` instead.
42
+ */
42
43
  error?: React.ReactNode;
44
+ errorMessage?: React.ReactNode;
43
45
  required?: boolean;
44
46
  className?: string;
45
47
  }
@@ -5,7 +5,12 @@ import { radioTheme } from './Radio.theme.js';
5
5
  import { formLabelTheme } from '../FormLabel/FormLabel.theme.js';
6
6
  import { RadioGroupContext } from './RadioContext.js';
7
7
 
8
- const RadioGroup = React__default.forwardRef(({ value: controlledValue, defaultValue, onChange, name, size = "md", state = "default", orientation = "vertical", label, description, error, required, className, children, ...props }, ref) => {
8
+ const RadioGroup = React__default.forwardRef(({ value: controlledValue, defaultValue, onChange, name, size = "md", state: stateProp = "default", orientation = "vertical", label, description, error, errorMessage, required, className, children, ...props }, ref) => {
9
+ // Prefer errorMessage; fall back to deprecated error prop
10
+ const resolvedError = errorMessage !== null && errorMessage !== void 0 ? errorMessage : error;
11
+ // If error (deprecated) is provided and state not explicitly set to something else,
12
+ // implicitly treat the group as invalid
13
+ const state = resolvedError && stateProp === "default" ? "invalid" : stateProp;
9
14
  const autoId = useId();
10
15
  const groupName = name !== null && name !== void 0 ? name : `radio-group-${autoId}`;
11
16
  const labelId = `${autoId}-label`;
@@ -28,8 +33,8 @@ const RadioGroup = React__default.forwardRef(({ value: controlledValue, defaultV
28
33
  size,
29
34
  state,
30
35
  }), [groupName, currentValue, size, state]);
31
- const labelState = error ? "invalid" : state === "disabled" ? "disabled" : "default";
32
- return (jsx(RadioGroupContext.Provider, { value: contextValue, children: jsxs("fieldset", { ref: ref, role: "radiogroup", "aria-labelledby": label ? labelId : undefined, "aria-describedby": description ? descriptionId : undefined, "aria-required": required || undefined, "aria-invalid": error ? true : undefined, "aria-errormessage": error ? errorId : undefined, className: cn("border-0 p-0 m-0", radioTheme.groupStyle, className), ...props, children: [label && (typeof label === 'string' ? (jsxs("legend", { id: labelId, className: cn(formLabelTheme.baseStyle, formLabelTheme.stateStyles[labelState]), children: [label, required && (jsx("span", { className: formLabelTheme.requiredIndicatorStyle, children: "*" }))] })) : label), description && (typeof description === 'string' ? (jsx("p", { id: descriptionId, className: radioTheme.groupDescriptionStyle, children: description })) : description), jsx("div", { className: cn(radioTheme.groupItemsStyle, orientation === "horizontal" && radioTheme.groupHorizontalStyle), children: children }), error && (typeof error === 'string' ? (jsx("p", { id: errorId, role: "alert", className: radioTheme.groupErrorStyle, children: error })) : error)] }) }));
36
+ const labelState = state === "invalid" ? "invalid" : state === "disabled" ? "disabled" : "default";
37
+ return (jsx(RadioGroupContext.Provider, { value: contextValue, children: jsxs("fieldset", { ref: ref, role: "radiogroup", "aria-labelledby": label ? labelId : undefined, "aria-describedby": description ? descriptionId : undefined, "aria-required": required || undefined, "aria-invalid": resolvedError ? true : undefined, "aria-errormessage": resolvedError ? errorId : undefined, className: cn("border-0 p-0 m-0", radioTheme.groupStyle, className), ...props, children: [label && (typeof label === 'string' ? (jsxs("legend", { id: labelId, className: cn(formLabelTheme.baseStyle, formLabelTheme.stateStyles[labelState]), children: [label, required && (jsx("span", { className: formLabelTheme.requiredIndicatorStyle, children: "*" }))] })) : label), description && (typeof description === 'string' ? (jsx("p", { id: descriptionId, className: radioTheme.groupDescriptionStyle, children: description })) : description), jsx("div", { className: cn(radioTheme.groupItemsStyle, orientation === "horizontal" && radioTheme.groupHorizontalStyle), children: children }), resolvedError && (typeof resolvedError === 'string' ? (jsx("p", { id: errorId, role: "alert", className: radioTheme.groupErrorStyle, children: resolvedError })) : resolvedError)] }) }));
33
38
  });
34
39
  RadioGroup.displayName = "Radio.Group";
35
40
 
@@ -416,6 +416,12 @@ const RichTextEditor = React__default.forwardRef(({ size = "md", state = "defaul
416
416
  setShowColorPicker(false);
417
417
  setShowFontSizePicker(false);
418
418
  }, [execEditorCommand]);
419
+ const handleMouseDown = useCallback((event) => {
420
+ event.preventDefault();
421
+ focusEditor();
422
+ }, [focusEditor]);
423
+ const fontSizeAnimations = useMemo(() => createDropdownAnimations(fontSizeIsFlipped), [fontSizeIsFlipped]);
424
+ const colorAnimations = useMemo(() => createDropdownAnimations(colorIsFlipped), [colorIsFlipped]);
419
425
  const handleAlign = useCallback((alignment) => {
420
426
  const commandMap = {
421
427
  left: "justifyLeft",
@@ -525,7 +531,7 @@ const RichTextEditor = React__default.forwardRef(({ size = "md", state = "defaul
525
531
  updateFormattingState();
526
532
  }
527
533
  }, [updateFormattingState, value, sanitizeHtml]);
528
- const renderToolbarTool = (tool, index) => {
534
+ const renderToolbarTool = (tool, toolKey) => {
529
535
  var _a, _b;
530
536
  const isActive = tool === "bold"
531
537
  ? formattingState.bold
@@ -543,21 +549,16 @@ const RichTextEditor = React__default.forwardRef(({ size = "md", state = "defaul
543
549
  ? formattingState.textAlign === "right"
544
550
  : false;
545
551
  const isFloatingToolbar = toolbarConfig.position === "floating";
546
- const handleMouseDown = (event) => {
547
- event.preventDefault();
548
- focusEditor();
549
- };
550
552
  switch (tool) {
551
553
  case "bold":
552
- return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), "data-state": isActive ? "active" : "inactive", "data-pressed": isActive ? "true" : "false", onMouseDown: handleMouseDown, onClick: handleBold, disabled: isDisabled, "aria-label": "Bold", "aria-pressed": isActive ? "true" : "false", children: jsx(BoldIcon, { className: "w-4 h-4" }) }, index));
554
+ return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), "data-state": isActive ? "active" : "inactive", "data-pressed": isActive ? "true" : "false", onMouseDown: handleMouseDown, onClick: handleBold, disabled: isDisabled, "aria-label": "Bold", "aria-pressed": isActive ? "true" : "false", children: jsx(BoldIcon, { className: "w-4 h-4" }) }, toolKey));
553
555
  case "italic":
554
- return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), "data-state": isActive ? "active" : "inactive", "data-pressed": isActive ? "true" : "false", onMouseDown: handleMouseDown, onClick: handleItalic, disabled: isDisabled, "aria-label": "Italic", "aria-pressed": isActive ? "true" : "false", children: jsx(ItalicIcon, { className: "w-4 h-4" }) }, index));
556
+ return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), "data-state": isActive ? "active" : "inactive", "data-pressed": isActive ? "true" : "false", onMouseDown: handleMouseDown, onClick: handleItalic, disabled: isDisabled, "aria-label": "Italic", "aria-pressed": isActive ? "true" : "false", children: jsx(ItalicIcon, { className: "w-4 h-4" }) }, toolKey));
555
557
  case "underline":
556
- return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), "data-state": isActive ? "active" : "inactive", "data-pressed": isActive ? "true" : "false", onMouseDown: handleMouseDown, onClick: handleUnderline, disabled: isDisabled, "aria-label": "Underline", "aria-pressed": isActive ? "true" : "false", children: jsx(UnderlineIcon, { className: "w-4 h-4" }) }, index));
558
+ return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), "data-state": isActive ? "active" : "inactive", "data-pressed": isActive ? "true" : "false", onMouseDown: handleMouseDown, onClick: handleUnderline, disabled: isDisabled, "aria-label": "Underline", "aria-pressed": isActive ? "true" : "false", children: jsx(UnderlineIcon, { className: "w-4 h-4" }) }, toolKey));
557
559
  case "fontSize": {
558
560
  const currentOption = getFontSizeOption(formattingState.fontSize);
559
561
  const dropdownClassName = themeStyles.dropdownStyle;
560
- const fontSizeAnimations = createDropdownAnimations(fontSizeIsFlipped);
561
562
  const dropdownList = (jsx("div", { className: dropdownClassName, role: "listbox", children: FONT_SIZE_OPTIONS.map((option) => (jsx("button", { className: cn(themeStyles.dropdownItemStyle, option.key === formattingState.fontSize
562
563
  ? "bg-[var(--color-primary-50)] text-[var(--color-primary-900)]"
563
564
  : undefined), "data-active": option.key === formattingState.fontSize ? "true" : "false", onMouseDown: (event) => {
@@ -599,12 +600,11 @@ const RichTextEditor = React__default.forwardRef(({ size = "md", state = "defaul
599
600
  focusEditor();
600
601
  setShowFontSizePicker((previous) => !previous);
601
602
  setShowColorPicker(false);
602
- }, disabled: isDisabled, "aria-label": "Font size", "aria-expanded": showFontSizePicker, "aria-haspopup": "listbox", children: jsx("span", { className: "text-sm font-medium tracking-wide uppercase", children: currentOption.label }) }), toolbarConfig.position === "floating" ? null : renderedDropdown, toolbarConfig.position === "floating" ? renderedDropdown : null] }, index));
603
+ }, disabled: isDisabled, "aria-label": "Font size", "aria-expanded": showFontSizePicker, "aria-haspopup": "listbox", children: jsx("span", { className: "text-sm font-medium tracking-wide uppercase", children: currentOption.label }) }), toolbarConfig.position === "floating" ? null : renderedDropdown, toolbarConfig.position === "floating" ? renderedDropdown : null] }, toolKey));
603
604
  }
604
605
  case "textColor":
605
606
  {
606
607
  const colorDropdownClassName = cn(themeStyles.dropdownStyle, themeStyles.colorPickerStyle);
607
- const colorAnimations = createDropdownAnimations(colorIsFlipped);
608
608
  const colorDropdownList = (jsx("div", { className: cn(colorDropdownClassName, "p-2"), children: colorOptions.map((color) => (jsx("button", { className: themeStyles.colorSwatchStyle, style: { backgroundColor: color.value }, onMouseDown: (event) => {
609
609
  event.preventDefault();
610
610
  focusEditor();
@@ -644,32 +644,32 @@ const RichTextEditor = React__default.forwardRef(({ size = "md", state = "defaul
644
644
  focusEditor();
645
645
  setShowFontSizePicker(false);
646
646
  setShowColorPicker((previous) => !previous);
647
- }, disabled: isDisabled, "aria-label": "Text Color", "aria-expanded": showColorPicker, children: jsx(PaintBrushIcon, { className: "w-4 h-4" }) }), isFloatingToolbar ? null : renderedColorDropdown, isFloatingToolbar ? renderedColorDropdown : null] }, index));
647
+ }, disabled: isDisabled, "aria-label": "Text Color", "aria-expanded": showColorPicker, children: jsx(PaintBrushIcon, { className: "w-4 h-4" }) }), isFloatingToolbar ? null : renderedColorDropdown, isFloatingToolbar ? renderedColorDropdown : null] }, toolKey));
648
648
  }
649
649
  case "alignLeft":
650
650
  return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), "data-state": isActive ? "active" : "inactive", "data-pressed": isActive ? "true" : "false", onMouseDown: handleMouseDown, onClick: (event) => {
651
651
  event.preventDefault();
652
652
  event.stopPropagation();
653
653
  handleAlign("left");
654
- }, disabled: isDisabled, "aria-label": "Align Left", "aria-pressed": isActive ? "true" : "false", children: jsx(Bars3BottomLeftIcon, { className: "w-4 h-4" }) }, index));
654
+ }, disabled: isDisabled, "aria-label": "Align Left", "aria-pressed": isActive ? "true" : "false", children: jsx(Bars3BottomLeftIcon, { className: "w-4 h-4" }) }, toolKey));
655
655
  case "alignCenter":
656
656
  return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), "data-state": isActive ? "active" : "inactive", "data-pressed": isActive ? "true" : "false", onMouseDown: handleMouseDown, onClick: (event) => {
657
657
  event.preventDefault();
658
658
  event.stopPropagation();
659
659
  handleAlign("center");
660
- }, disabled: isDisabled, "aria-label": "Align Center", "aria-pressed": isActive ? "true" : "false", children: jsx(Bars3Icon, { className: "w-4 h-4" }) }, index));
660
+ }, disabled: isDisabled, "aria-label": "Align Center", "aria-pressed": isActive ? "true" : "false", children: jsx(Bars3Icon, { className: "w-4 h-4" }) }, toolKey));
661
661
  case "alignRight":
662
662
  return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), "data-state": isActive ? "active" : "inactive", "data-pressed": isActive ? "true" : "false", onMouseDown: handleMouseDown, onClick: (event) => {
663
663
  event.preventDefault();
664
664
  event.stopPropagation();
665
665
  handleAlign("right");
666
- }, disabled: isDisabled, "aria-label": "Align Right", "aria-pressed": isActive ? "true" : "false", children: jsx(Bars3BottomRightIcon, { className: "w-4 h-4" }) }, index));
666
+ }, disabled: isDisabled, "aria-label": "Align Right", "aria-pressed": isActive ? "true" : "false", children: jsx(Bars3BottomRightIcon, { className: "w-4 h-4" }) }, toolKey));
667
667
  case "undo":
668
- return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), onMouseDown: handleMouseDown, onClick: handleUndo, disabled: isDisabled, "aria-label": "Undo", children: jsx(ArrowUturnLeftIcon, { className: "w-4 h-4" }) }, index));
668
+ return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), onMouseDown: handleMouseDown, onClick: handleUndo, disabled: isDisabled, "aria-label": "Undo", children: jsx(ArrowUturnLeftIcon, { className: "w-4 h-4" }) }, toolKey));
669
669
  case "redo":
670
- return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), onMouseDown: handleMouseDown, onClick: handleRedo, disabled: isDisabled, "aria-label": "Redo", children: jsx(ArrowUturnRightIcon, { className: "w-4 h-4" }) }, index));
670
+ return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), onMouseDown: handleMouseDown, onClick: handleRedo, disabled: isDisabled, "aria-label": "Redo", children: jsx(ArrowUturnRightIcon, { className: "w-4 h-4" }) }, toolKey));
671
671
  case "separator":
672
- return jsx("div", { className: themeStyles.separatorStyle }, index);
672
+ return jsx("div", { className: themeStyles.separatorStyle }, toolKey);
673
673
  default:
674
674
  return null;
675
675
  }
@@ -678,13 +678,13 @@ const RichTextEditor = React__default.forwardRef(({ size = "md", state = "defaul
678
678
  if (!toolbarConfig.show || !toolbarConfig.tools)
679
679
  return null;
680
680
  const toolbarClass = cn(themeStyles.toolbarStyle, toolbarConfig.className);
681
- const toolbarContent = (jsx("div", { ref: toolbarRef, className: toolbarClass, children: toolbarConfig.tools.map((tool, index) => renderToolbarTool(tool, index)) }));
681
+ const toolbarContent = (jsx("div", { ref: toolbarRef, className: toolbarClass, children: toolbarConfig.tools.map((tool) => renderToolbarTool(tool, tool)) }));
682
682
  if (toolbarConfig.position === "floating") {
683
683
  return (jsx(AnimatePresence, { mode: "wait", children: showToolbar && (jsx(motion.div, { variants: shouldReduceMotion ? undefined : floatingToolbarVariants, initial: "initial", animate: "animate", exit: "exit", className: "bg-white/70 backdrop-blur-sm shadow-2xl rounded-xl border border-[var(--color-border)] overflow-hidden", style: { position: "absolute", top: toolbarPosition.top, left: toolbarPosition.left, zIndex: 50 }, children: toolbarContent }, "floating-toolbar")) }));
684
684
  }
685
685
  return toolbarContent;
686
686
  };
687
- return (jsxs("div", { className: cn(themeStyles.wrapperStyle, className), ...props, children: [label && (jsx("div", { className: "mb-1", children: jsx(FormLabel, { htmlFor: editorId, className: labelClassName, state: state, required: required, children: label }) })), jsxs("div", { className: "relative", children: [jsxs("div", { className: cn(themeStyles.containerStyle, themeStyles.states[state], themeStyles.sizes[size]), "data-state": getDataState(), children: [toolbarConfig.position === "top" && renderToolbar(), jsx("div", { ref: (el) => {
687
+ return (jsxs("div", { className: cn(themeStyles.wrapperStyle, className), ...props, children: [label && (typeof label === 'string' ? (jsx("div", { className: "mb-1", children: jsx(FormLabel, { htmlFor: editorId, className: labelClassName, state: state, required: required, children: label }) })) : (label)), jsxs("div", { className: "relative", children: [jsxs("div", { className: cn(themeStyles.containerStyle, themeStyles.states[state], themeStyles.sizes[size]), "data-state": getDataState(), children: [toolbarConfig.position === "top" && renderToolbar(), jsx("div", { ref: (el) => {
688
688
  if (el) {
689
689
  editorRef.current = el;
690
690
  if (typeof ref === "function") {
@@ -704,7 +704,7 @@ const RichTextEditor = React__default.forwardRef(({ size = "md", state = "defaul
704
704
  }
705
705
  setShowColorPicker(false);
706
706
  setShowFontSizePicker(false);
707
- }, "aria-invalid": isInvalid, "aria-required": required, role: "textbox", "aria-multiline": "true", "aria-label": label || "Rich text editor", suppressContentEditableWarning: true })] }), toolbarConfig.position === "floating" && renderToolbar()] }), helperText && (jsx("div", { className: cn(themeStyles.helperText, helperTextClassName), children: helperText }))] }));
707
+ }, "aria-invalid": isInvalid, "aria-required": required, role: "textbox", "aria-multiline": "true", "aria-label": typeof label === 'string' ? label : "Rich text editor", suppressContentEditableWarning: true })] }), toolbarConfig.position === "floating" && renderToolbar()] }), helperText && (typeof helperText === 'string' ? (jsx("div", { className: cn(themeStyles.helperText, helperTextClassName), children: helperText })) : (helperText))] }));
708
708
  });
709
709
  RichTextEditor.displayName = "RichTextEditor";
710
710
 
@@ -19,9 +19,9 @@ export interface RichTextEditorProps extends Omit<React.HTMLAttributes<HTMLDivEl
19
19
  /** The state of the editor (default, disabled, invalid) */
20
20
  state?: RichTextEditorState;
21
21
  /** Optional label text for the editor */
22
- label?: string;
22
+ label?: React.ReactNode;
23
23
  /** Optional helper text displayed below the editor */
24
- helperText?: string;
24
+ helperText?: React.ReactNode;
25
25
  /** The HTML content value */
26
26
  value?: string;
27
27
  /** Callback when content changes */
@@ -79,6 +79,8 @@ export declare const SelectButton: React.FC<SelectButtonProps>;
79
79
  export interface SelectOptionsExtendedProps extends SelectOptionsProps {
80
80
  /** Custom trigger ref - if provided, uses this instead of buttonRef from context */
81
81
  triggerRef?: React.RefObject<HTMLElement>;
82
+ /** id applied to the listbox element for aria-controls matching */
83
+ listboxId?: string;
82
84
  }
83
85
  /**
84
86
  * Select Options Component