@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.
- package/dist/components/ai/PromptInput/PromptInput.js +139 -7
- package/dist/components/ai/PromptInput/VoiceRecorder.js +84 -0
- package/dist/components/charts/AreaChart/AreaChart.types.d.ts +2 -2
- package/dist/components/charts/BarChart/BarChart.types.d.ts +2 -2
- package/dist/components/charts/ComboChart/ComboChart.types.d.ts +2 -2
- package/dist/components/charts/LineChart/LineChart.types.d.ts +2 -2
- package/dist/components/charts/ScatterPlot/ScatterPlot.types.d.ts +2 -2
- package/dist/components/charts/StackedBarChart/StackedBarChart.types.d.ts +2 -2
- package/dist/components/core/Accordion/AccordionTrigger.js +28 -1
- package/dist/components/core/Alert/Alert.js +2 -1
- package/dist/components/core/AlertDialog/AlertDialog.js +1 -1
- package/dist/components/core/Badge/Badge.js +6 -17
- package/dist/components/core/Breadcrumbs/Breadcrumbs.js +17 -28
- package/dist/components/core/Calendar/Calendar.js +1 -1
- package/dist/components/core/Carousel/CarouselBody.js +6 -1
- package/dist/components/core/ContextMenu/ContextMenuBody.js +6 -3
- package/dist/components/core/ContextMenu/ContextMenuSubBody.js +6 -3
- package/dist/components/core/DragDrop/DragDrop.js +170 -17
- package/dist/components/core/DragDrop/DragDrop.types.d.ts +6 -0
- package/dist/components/core/Drawer/Drawer.d.ts +1 -1
- package/dist/components/core/Drawer/Drawer.js +2 -0
- package/dist/components/core/Drawer/Drawer.types.d.ts +2 -0
- package/dist/components/core/Drawer/DrawerTitle.d.ts +1 -1
- package/dist/components/core/Drawer/DrawerTitle.js +2 -2
- package/dist/components/core/Dropdown/DropdownMenu.js +2 -30
- package/dist/components/core/Masonry/Masonry.js +7 -2
- package/dist/components/core/Modal/Modal.d.ts +1 -1
- package/dist/components/core/Modal/Modal.js +3 -3
- package/dist/components/core/Modal/Modal.types.d.ts +2 -0
- package/dist/components/core/Modal/ModalTitle.d.ts +1 -1
- package/dist/components/core/Modal/ModalTitle.js +2 -2
- package/dist/components/core/NavItem/NavItem.js +21 -6
- package/dist/components/core/NavItem/NavItem.theme.js +2 -2
- package/dist/components/core/Pagination/Pagination.js +1 -1
- package/dist/components/core/Popover/PopoverBody.js +3 -27
- package/dist/components/core/Popover/PopoverTrigger.js +1 -1
- package/dist/components/core/Progress/Progress.js +4 -4
- package/dist/components/core/Rating/Rating.js +1 -1
- package/dist/components/core/ScrollArea/ScrollArea.js +3 -2
- package/dist/components/core/Segmented/Segmented.js +6 -6
- package/dist/components/core/Segmented/SegmentedItem.js +28 -2
- package/dist/components/core/Sidebar/Sidebar.d.ts +1 -0
- package/dist/components/core/Sidebar/Sidebar.js +5 -3
- package/dist/components/core/Sidebar/Sidebar.types.d.ts +7 -1
- package/dist/components/core/Sidebar/SidebarContent.js +1 -1
- package/dist/components/core/Sidebar/SidebarFooter.js +1 -1
- package/dist/components/core/Sidebar/SidebarHeader.js +5 -2
- package/dist/components/core/Sidebar/SidebarLogo.d.ts +3 -0
- package/dist/components/core/Sidebar/SidebarLogo.js +17 -0
- package/dist/components/core/Sidebar/SidebarNavGroup.js +2 -1
- package/dist/components/core/Sidebar/SidebarToggle.js +2 -4
- package/dist/components/core/Sidebar/SidebarUserProfile.js +3 -6
- package/dist/components/core/Sidebar/index.d.ts +2 -1
- package/dist/components/core/Skeleton/Skeleton.js +2 -2
- package/dist/components/core/Sortable/Sortable.d.ts +1 -1
- package/dist/components/core/Sortable/Sortable.js +20 -4
- package/dist/components/core/Sortable/Sortable.types.d.ts +2 -0
- package/dist/components/core/Tabs/Tabs.js +6 -4
- package/dist/components/core/Tabs/Tabs.types.d.ts +2 -0
- package/dist/components/core/Tabs/TabsBody.js +3 -3
- package/dist/components/core/Tabs/TabsList.js +19 -21
- package/dist/components/core/Tabs/TabsTrigger.js +47 -28
- package/dist/components/core/Toast/Toast.js +1 -1
- package/dist/components/core/Toast/ToastProvider.js +3 -2
- package/dist/components/core/Tooltip/Tooltip.d.ts +1 -1
- package/dist/components/core/Tooltip/Tooltip.js +26 -35
- package/dist/components/core/Tooltip/Tooltip.types.d.ts +5 -1
- package/dist/components/core/Tree/Tree.js +178 -8
- package/dist/components/core/index.js +1 -0
- package/dist/components/data-display/GanttChart/GanttSplitter.js +15 -1
- package/dist/components/data-display/Table/Table.js +2 -2
- package/dist/components/data-display/Table/Table.types.d.ts +2 -0
- package/dist/components/data-display/Table/TableFilter.js +21 -18
- package/dist/components/effects/CustomCursor/CustomCursor.js +3 -7
- package/dist/components/effects/Overlay/Overlay.js +4 -9
- package/dist/components/effects/PageTransition/PageTransition.js +17 -6
- package/dist/components/effects/SpotlightBorder/SpotlightBorder.js +3 -4
- package/dist/components/forms/Checkbox/Checkbox.js +11 -1
- package/dist/components/forms/Checkbox/Checkbox.theme.js +4 -1
- package/dist/components/forms/Checkbox/Checkbox.types.d.ts +7 -5
- package/dist/components/forms/Checkbox/CheckboxGroup.js +9 -4
- package/dist/components/forms/ColorPicker/ColorPicker.js +7 -4
- package/dist/components/forms/ColorPicker/ColorPicker.types.d.ts +2 -2
- package/dist/components/forms/ColorPicker/ColorPickerBody.js +5 -3
- package/dist/components/forms/ColorPicker/ColorPickerEyeDropper.js +3 -3
- package/dist/components/forms/ColorPicker/ColorPickerGradient.js +8 -8
- package/dist/components/forms/ColorPicker/ColorPickerInput.js +1 -1
- package/dist/components/forms/ColorPicker/index.d.ts +1 -1
- package/dist/components/forms/Combobox/Combobox.js +20 -45
- package/dist/components/forms/Combobox/Combobox.types.d.ts +4 -2
- package/dist/components/forms/CronInput/CronInput.js +10 -4
- package/dist/components/forms/CronInput/CronInput.types.d.ts +12 -1
- package/dist/components/forms/DatePicker/DatePicker.js +2 -2
- package/dist/components/forms/DatePicker/DatePicker.types.d.ts +4 -2
- package/dist/components/forms/DatePicker/DatePickerBody.js +1 -29
- package/dist/components/forms/DatePicker/DatePickerTrigger.js +2 -2
- package/dist/components/forms/DateRangePicker/DateRangePicker.js +3 -3
- package/dist/components/forms/DateRangePicker/DateRangePicker.types.d.ts +4 -2
- package/dist/components/forms/DateRangePicker/DateRangePickerBody.js +1 -28
- package/dist/components/forms/DateRangePicker/DateRangePickerTrigger.js +2 -2
- package/dist/components/forms/FileUpload/FileUpload.js +99 -10
- package/dist/components/forms/FileUpload/FileUpload.types.d.ts +15 -0
- package/dist/components/forms/FormLabel/FormLabel.js +2 -2
- package/dist/components/forms/Input/Input.js +5 -3
- package/dist/components/forms/Input/Input.types.d.ts +2 -0
- package/dist/components/forms/InputAddress/InputAddress.d.ts +1 -1
- package/dist/components/forms/InputAddress/InputAddress.js +8 -9
- package/dist/components/forms/InputCounter/InputCounter.js +25 -18
- package/dist/components/forms/InputCounter/InputCounter.types.d.ts +8 -1
- package/dist/components/forms/InputCreditCard/InputCreditCard.d.ts +1 -1
- package/dist/components/forms/InputCreditCard/InputCreditCard.js +27 -9
- package/dist/components/forms/InputCreditCard/InputCreditCard.types.d.ts +5 -0
- package/dist/components/forms/InputOTP/InputOTP.js +26 -17
- package/dist/components/forms/InputOTP/InputOTP.types.d.ts +21 -4
- package/dist/components/forms/InputTag/InputTag.js +12 -39
- package/dist/components/forms/InputTag/InputTag.types.d.ts +2 -2
- package/dist/components/forms/Mention/Mention.js +13 -6
- package/dist/components/forms/Mention/Mention.types.d.ts +9 -0
- package/dist/components/forms/Radio/Radio.js +12 -2
- package/dist/components/forms/Radio/Radio.theme.js +5 -1
- package/dist/components/forms/Radio/Radio.types.d.ts +7 -5
- package/dist/components/forms/Radio/RadioGroup.js +8 -3
- package/dist/components/forms/RichTextEditor/RichTextEditor.js +21 -21
- package/dist/components/forms/RichTextEditor/RichTextEditor.types.d.ts +2 -2
- package/dist/components/forms/Select/Select.d.ts +2 -0
- package/dist/components/forms/Select/Select.js +26 -56
- package/dist/components/forms/Select/Select.types.d.ts +14 -0
- package/dist/components/forms/Signature/Signature.js +1 -1
- package/dist/components/forms/Signature/Signature.types.d.ts +3 -3
- package/dist/components/forms/Slider/Slider.js +18 -4
- package/dist/components/forms/Slider/Slider.types.d.ts +2 -2
- package/dist/components/forms/Switch/Switch.js +12 -19
- package/dist/components/forms/Switch/Switch.theme.js +12 -2
- package/dist/components/forms/Switch/Switch.types.d.ts +20 -2
- package/dist/components/forms/Textarea/Textarea.js +8 -3
- package/dist/components/forms/Textarea/Textarea.types.d.ts +2 -0
- package/dist/components/forms/TimePicker/TimePicker.js +1 -1
- package/dist/components/forms/TimePicker/TimePicker.types.d.ts +6 -2
- package/dist/components/forms/TimePicker/TimePickerContent.js +88 -30
- package/dist/components/forms/TimePicker/TimePickerTrigger.js +2 -2
- package/dist/components/forms/index.js +86 -1
- package/dist/components/layout/FormLayout/FormLayout.js +87 -1
- package/dist/components/layout/index.js +4 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/useClickOutside.d.ts +10 -4
- package/dist/hooks/useClickOutside.js +44 -24
- package/dist/hooks/useDarkMode.d.ts +1 -0
- package/dist/hooks/useDarkMode.js +42 -0
- package/dist/hooks/useFormStateMachine.d.ts +1 -1
- package/dist/hooks/useNetworkStatus.js +1 -1
- package/dist/hooks/useOverlay.js +4 -0
- package/dist/hooks/useScaleBackground.js +5 -2
- package/dist/hooks/useSelectPortal.js +14 -5
- package/dist/index.d.ts +0 -2
- package/dist/index.js +174 -223
- package/dist/shadcn-compat.css +80 -0
- package/dist/styles.css +1 -1
- package/dist/utils/stateMachine.d.ts +4 -4
- package/package.json +12 -10
- package/tailwind.preset.cjs +32 -3
- /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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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?:
|
|
36
|
+
label?: React.ReactNode;
|
|
37
37
|
/** Helper text displayed below the tags */
|
|
38
|
-
helperText?:
|
|
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]);
|
|
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
|
-
|
|
600
|
-
|
|
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 }) }),
|
|
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
|
-
|
|
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.
|
|
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 =
|
|
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":
|
|
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,
|
|
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" }) },
|
|
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" }) },
|
|
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" }) },
|
|
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] },
|
|
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] },
|
|
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" }) },
|
|
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" }) },
|
|
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" }) },
|
|
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" }) },
|
|
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" }) },
|
|
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 },
|
|
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
|
|
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
|
|
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?:
|
|
22
|
+
label?: React.ReactNode;
|
|
23
23
|
/** Optional helper text displayed below the editor */
|
|
24
|
-
helperText?:
|
|
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
|