@flikk/ui 1.0.0-beta.23 → 1.0.0-beta.25
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/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/Accordion.theme.js +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/Breadcrumbs/Breadcrumbs.theme.js +2 -2
- package/dist/components/core/Calendar/Calendar.js +1 -1
- package/dist/components/core/Calendar/CalendarMini/CalendarMini.js +4 -2
- package/dist/components/core/Calendar/CalendarMini/CalendarMini.theme.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/Empty/Empty.theme.js +1 -1
- package/dist/components/core/Link/Link.js +1 -1
- 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 +13 -8
- 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/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.js +25 -34
- package/dist/components/core/Tree/Tree.js +178 -8
- 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/data-display/Timeline/Timeline.animations.d.ts +0 -7
- package/dist/components/data-display/Timeline/Timeline.animations.js +1 -27
- package/dist/components/data-display/Timeline/Timeline.js +3 -4
- package/dist/components/data-display/Timeline/Timeline.types.d.ts +0 -13
- package/dist/components/data-display/Timeline/TimelineContent.js +3 -7
- package/dist/components/data-display/Timeline/TimelineItem.js +4 -17
- package/dist/components/data-display/Timeline/index.d.ts +2 -2
- 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/effects/index.d.ts +7 -0
- package/dist/components/effects/index.js +3 -0
- 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 +14 -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 +27 -57
- 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 +2 -29
- package/dist/components/forms/TimePicker/TimePickerTrigger.js +2 -2
- package/dist/components/forms/index.js +1 -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 +1 -57
- package/dist/shadcn-compat.css +80 -0
- package/dist/styles.css +1 -1
- package/dist/utils/stateMachine.d.ts +4 -4
- package/package.json +11 -10
- package/tailwind.preset.cjs +32 -3
- /package/{src/theme-plugin.css → dist/theme.css} +0 -0
|
@@ -8,8 +8,10 @@ import { cn } from '../../../utils/cn.js';
|
|
|
8
8
|
/**
|
|
9
9
|
* Switch component for toggling between two states
|
|
10
10
|
*/
|
|
11
|
-
const Switch = React__default.forwardRef(({ id, checked: controlledChecked, onChange, label, description, state = "default", labelPosition = "end", theme, className, ...rest }, ref) => {
|
|
12
|
-
const
|
|
11
|
+
const Switch = React__default.forwardRef(({ id, checked: controlledChecked, defaultChecked, onChange, label, description, state = "default", labelPosition = "end", size = "md", theme, className, name, value, required, form, ...rest }, ref) => {
|
|
12
|
+
const generatedId = React__default.useId();
|
|
13
|
+
const switchId = id !== null && id !== void 0 ? id : generatedId;
|
|
14
|
+
const [internalChecked, setInternalChecked] = useState(defaultChecked !== null && defaultChecked !== void 0 ? defaultChecked : false);
|
|
13
15
|
// Determine if component is controlled or uncontrolled
|
|
14
16
|
const isControlled = controlledChecked !== undefined;
|
|
15
17
|
const isChecked = isControlled ? controlledChecked : internalChecked;
|
|
@@ -24,18 +26,9 @@ const Switch = React__default.forwardRef(({ id, checked: controlledChecked, onCh
|
|
|
24
26
|
}
|
|
25
27
|
onChange === null || onChange === void 0 ? void 0 : onChange(e.target.checked);
|
|
26
28
|
};
|
|
27
|
-
const handleTrackClick = () => {
|
|
28
|
-
if (!isDisabled) {
|
|
29
|
-
const newValue = !isChecked;
|
|
30
|
-
if (!isControlled) {
|
|
31
|
-
setInternalChecked(newValue);
|
|
32
|
-
}
|
|
33
|
-
onChange === null || onChange === void 0 ? void 0 : onChange(newValue);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
29
|
// Label and description content
|
|
37
30
|
const labelContent = label || description ? (jsxs("div", { className: "flex grow flex-col", children: [label &&
|
|
38
|
-
(typeof label === "string" ? (jsx(FormLabel, { htmlFor:
|
|
31
|
+
(typeof label === "string" ? (jsx(FormLabel, { htmlFor: switchId, state: state, children: label })) : (label)), description &&
|
|
39
32
|
(typeof description === "string" ? (jsx("div", { className: cn(switchTheme.description, theme === null || theme === void 0 ? void 0 : theme.description), children: description })) : (description))] })) : null;
|
|
40
33
|
// Build data attributes for state-based styling
|
|
41
34
|
const trackDataState = isDisabled
|
|
@@ -45,14 +38,14 @@ const Switch = React__default.forwardRef(({ id, checked: controlledChecked, onCh
|
|
|
45
38
|
: isChecked
|
|
46
39
|
? "checked"
|
|
47
40
|
: "unchecked";
|
|
48
|
-
const filterId = `switch-liquid-lens-${
|
|
41
|
+
const filterId = `switch-liquid-lens-${switchId}`;
|
|
49
42
|
// Switch toggle component
|
|
50
|
-
const switchToggle = (jsxs("div", { className: "relative flex items-center h-6", children: [jsx("
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
43
|
+
const switchToggle = (jsxs("div", { className: "relative flex items-center h-6", children: [jsx("svg", { width: "0", height: "0", className: "absolute", "aria-hidden": "true", children: jsx("defs", { children: jsxs("filter", { id: filterId, children: [jsx("feGaussianBlur", { in: "SourceGraphic", stdDeviation: "1", result: "blur" }), jsx("feColorMatrix", { in: "blur", type: "matrix", values: "1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7", result: "goo" }), jsx("feComposite", { in: "SourceGraphic", in2: "goo", operator: "atop" })] }) }) }), jsxs("label", { htmlFor: switchId, className: "contents", children: [jsx("input", { ref: ref, type: "checkbox", id: switchId, checked: isChecked, onChange: handleChange, disabled: isDisabled, className: "sr-only", name: name, value: value, required: required, form: form }), jsx("div", { className: cn(switchTheme.track, switchTheme.trackSizes[size], theme === null || theme === void 0 ? void 0 : theme.track), "data-state": trackDataState, "aria-hidden": "true", children: jsxs(motion.div, { className: cn(switchTheme.thumb, switchTheme.thumbSizes[size], theme === null || theme === void 0 ? void 0 : theme.thumb), initial: false, animate: isChecked ? thumbPositions.checked : thumbPositions.unchecked, transition: { type: "spring", stiffness: 500, damping: 30 }, whileTap: isDisabled ? undefined : { scale: 1.15 }, style: { filter: `url(#${filterId})` }, children: [jsx("div", { className: "absolute inset-0 z-0 rounded-full", style: {
|
|
44
|
+
backdropFilter: "blur(0.6px)",
|
|
45
|
+
WebkitBackdropFilter: "blur(0.6px)",
|
|
46
|
+
}, "aria-hidden": "true" }), jsx("div", { className: "absolute inset-0 z-[1] rounded-full bg-[var(--color-surface)]/80", "aria-hidden": "true" }), jsx("div", { className: "absolute inset-0 z-[2] rounded-full", style: {
|
|
47
|
+
boxShadow: "inset 1px 1px 0 rgba(255,255,255,0.35), inset 1px 3px 0 rgba(0,0,0,0.03), inset 0 0 14px rgba(255,255,255,0.25), inset -1px -1px 0 rgba(0,0,0,0.06)",
|
|
48
|
+
}, "aria-hidden": "true" })] }) })] })] }));
|
|
56
49
|
return (jsxs("div", { className: cn(switchTheme.container, labelPosition === "start" ? "flex-row-reverse" : "flex-row", theme === null || theme === void 0 ? void 0 : theme.container, className), ...rest, children: [labelContent, switchToggle] }));
|
|
57
50
|
});
|
|
58
51
|
Switch.displayName = "Switch";
|
|
@@ -3,9 +3,19 @@
|
|
|
3
3
|
*/
|
|
4
4
|
const switchTheme = {
|
|
5
5
|
container: "flex w-full justify-between items-center gap-4",
|
|
6
|
-
track: "
|
|
7
|
-
thumb: "
|
|
6
|
+
track: "rounded-full cursor-pointer shadow-inner bg-[var(--color-background-tertiary)] data-[state=checked]:bg-[var(--color-primary)] data-[state=disabled]:bg-[var(--color-background-disabled)] data-[state=disabled]:cursor-not-allowed data-[state=invalid]:border-2 data-[state=invalid]:border-[var(--color-danger)] outline outline-[var(--color-border)] transition-colors duration-300",
|
|
7
|
+
thumb: "rounded-full bg-transparent overflow-hidden border border-[var(--color-border)]/40 shadow-lg",
|
|
8
8
|
description: "text-sm text-[var(--color-text-muted)] -mt-1.5",
|
|
9
|
+
trackSizes: {
|
|
10
|
+
sm: "w-9 h-5",
|
|
11
|
+
md: "w-12 h-6",
|
|
12
|
+
lg: "w-14 h-7",
|
|
13
|
+
},
|
|
14
|
+
thumbSizes: {
|
|
15
|
+
sm: "w-5 h-4",
|
|
16
|
+
md: "w-7 h-5",
|
|
17
|
+
lg: "w-8 h-6",
|
|
18
|
+
},
|
|
9
19
|
};
|
|
10
20
|
/**
|
|
11
21
|
* Thumb position values for animation
|
|
@@ -6,14 +6,20 @@ export type SwitchLabelPosition = "start" | "end";
|
|
|
6
6
|
* State variants for the switch component
|
|
7
7
|
*/
|
|
8
8
|
export type SwitchState = 'default' | 'disabled' | 'invalid';
|
|
9
|
+
/**
|
|
10
|
+
* Size variants for the switch component
|
|
11
|
+
*/
|
|
12
|
+
export type SwitchSize = 'sm' | 'md' | 'lg';
|
|
9
13
|
/**
|
|
10
14
|
* Switch component props
|
|
11
15
|
*/
|
|
12
16
|
export interface SwitchProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
|
|
13
|
-
/** Unique identifier for the switch input */
|
|
14
|
-
id
|
|
17
|
+
/** Unique identifier for the switch input — if omitted, one is generated via React.useId() */
|
|
18
|
+
id?: string;
|
|
15
19
|
/** Whether the switch is checked (controlled mode) */
|
|
16
20
|
checked?: boolean;
|
|
21
|
+
/** Initial checked state for uncontrolled mode */
|
|
22
|
+
defaultChecked?: boolean;
|
|
17
23
|
/** Function called when the switch state changes */
|
|
18
24
|
onChange?: (checked: boolean) => void;
|
|
19
25
|
/** Label for the switch — pass a string for default styling, or a ReactNode for full control */
|
|
@@ -24,8 +30,18 @@ export interface SwitchProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
|
|
|
24
30
|
state?: SwitchState;
|
|
25
31
|
/** Position of the label relative to the switch */
|
|
26
32
|
labelPosition?: SwitchLabelPosition;
|
|
33
|
+
/** Size of the switch track and thumb */
|
|
34
|
+
size?: SwitchSize;
|
|
27
35
|
/** Optional theme overrides */
|
|
28
36
|
theme?: SwitchThemeOverrides;
|
|
37
|
+
/** HTML name attribute for the hidden input */
|
|
38
|
+
name?: string;
|
|
39
|
+
/** HTML value attribute for the hidden input */
|
|
40
|
+
value?: string;
|
|
41
|
+
/** Whether the hidden input is required */
|
|
42
|
+
required?: boolean;
|
|
43
|
+
/** The id of the form this input belongs to */
|
|
44
|
+
form?: string;
|
|
29
45
|
}
|
|
30
46
|
/**
|
|
31
47
|
* Switch theme configuration
|
|
@@ -35,6 +51,8 @@ export interface SwitchTheme {
|
|
|
35
51
|
track: string;
|
|
36
52
|
thumb: string;
|
|
37
53
|
description: string;
|
|
54
|
+
trackSizes: Record<SwitchSize, string>;
|
|
55
|
+
thumbSizes: Record<SwitchSize, string>;
|
|
38
56
|
}
|
|
39
57
|
/**
|
|
40
58
|
* Switch theme overrides
|
|
@@ -4,7 +4,7 @@ import { FormLabel } from '../FormLabel/FormLabel.js';
|
|
|
4
4
|
import { textareaTheme } from './Textarea.theme.js';
|
|
5
5
|
import { cn } from '../../../utils/cn.js';
|
|
6
6
|
|
|
7
|
-
const Textarea = React__default.forwardRef(({ size = "md", state = "default", className = "", label, labelClassName = "", helperText, helperTextClassName = "", wrapperClassName = "", inputGroupClassName = "", id, theme = {}, required, rows = 3, cols, unstyled = false, ...props }, ref) => {
|
|
7
|
+
const Textarea = React__default.forwardRef(({ size = "md", state = "default", className = "", label, labelClassName = "", helperText, helperTextClassName = "", wrapperClassName = "", inputGroupClassName = "", id, theme = {}, required, rows = 3, cols, unstyled = false, onValueChange, ...props }, ref) => {
|
|
8
8
|
var _a, _b, _c, _d;
|
|
9
9
|
const [isFocused, setIsFocused] = useState(false);
|
|
10
10
|
const generatedId = React__default.useId();
|
|
@@ -30,6 +30,8 @@ const Textarea = React__default.forwardRef(({ size = "md", state = "default", cl
|
|
|
30
30
|
: isDisabled
|
|
31
31
|
? "state-disabled"
|
|
32
32
|
: "state-default";
|
|
33
|
+
// Pull onChange out of props so the explicit handler below isn't overwritten by the spread
|
|
34
|
+
const { onChange: propsOnChange, ...restProps } = props;
|
|
33
35
|
// Get theme classes
|
|
34
36
|
const wrapperClasses = theme.wrapperStyle || textareaTheme.wrapperStyle || "";
|
|
35
37
|
const inputGroupClasses = theme.inputGroupStyle || textareaTheme.inputGroupStyle || "";
|
|
@@ -37,7 +39,7 @@ const Textarea = React__default.forwardRef(({ size = "md", state = "default", cl
|
|
|
37
39
|
const sizeClasses = ((_a = theme.sizes) === null || _a === void 0 ? void 0 : _a[size]) || ((_b = textareaTheme.sizes) === null || _b === void 0 ? void 0 : _b[size]) || "";
|
|
38
40
|
const stateClasses = ((_c = theme.states) === null || _c === void 0 ? void 0 : _c[state]) || ((_d = textareaTheme.states) === null || _d === void 0 ? void 0 : _d[state]) || "";
|
|
39
41
|
const helperTextClasses = theme.helperText || textareaTheme.helperText || "";
|
|
40
|
-
return (jsxs("div", { className: cn(wrapperClasses, stateClass, wrapperClassName), children: [label && (typeof label === 'string' ? (jsx("div", { className: "mb-1", children: jsx(FormLabel, { htmlFor: inputId, className: labelClassName, state: state, required: required, children: label }) })) : (label)), jsx("div", { children: jsx("div", { className: cn(inputGroupClasses, stateClasses, inputGroupClassName), children: jsx("div", { className: "relative flex-1", children: jsx("textarea", { ref: ref, id: inputId, className: cn(baseClasses, sizeClasses, className), disabled: isDisabled, "aria-invalid": isInvalid, required: required, rows: rows, cols: cols, onFocus: (e) => {
|
|
42
|
+
return (jsxs("div", { className: cn(wrapperClasses, stateClass, wrapperClassName), children: [label && (typeof label === 'string' ? (jsx("div", { className: "mb-1", children: jsx(FormLabel, { htmlFor: inputId, className: labelClassName, state: state, required: required, children: label }) })) : (label)), jsx("div", { children: jsx("div", { className: cn(inputGroupClasses, stateClasses, inputGroupClassName), children: jsx("div", { className: "relative flex-1", children: jsx("textarea", { ref: ref, id: inputId, className: cn(baseClasses, sizeClasses, className), disabled: isDisabled, "aria-invalid": isInvalid, "aria-describedby": helperText ? `${inputId}-helper` : undefined, required: required, rows: rows, cols: cols, onFocus: (e) => {
|
|
41
43
|
var _a;
|
|
42
44
|
setIsFocused(true);
|
|
43
45
|
(_a = props.onFocus) === null || _a === void 0 ? void 0 : _a.call(props, e);
|
|
@@ -45,7 +47,10 @@ const Textarea = React__default.forwardRef(({ size = "md", state = "default", cl
|
|
|
45
47
|
var _a;
|
|
46
48
|
setIsFocused(false);
|
|
47
49
|
(_a = props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, e);
|
|
48
|
-
},
|
|
50
|
+
}, onChange: (e) => {
|
|
51
|
+
propsOnChange === null || propsOnChange === void 0 ? void 0 : propsOnChange(e);
|
|
52
|
+
onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(e.target.value);
|
|
53
|
+
}, ...restProps }) }) }) }), helperText && (typeof helperText === 'string' ? (jsx("div", { id: `${inputId}-helper`, className: cn(helperTextClasses, helperTextClassName), children: helperText })) : (helperText))] }));
|
|
49
54
|
});
|
|
50
55
|
Textarea.displayName = "Textarea";
|
|
51
56
|
|
|
@@ -35,6 +35,8 @@ export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextArea
|
|
|
35
35
|
cols?: number;
|
|
36
36
|
/** Render only the textarea element without wrapper, label, or helper text */
|
|
37
37
|
unstyled?: boolean;
|
|
38
|
+
/** Callback fired with the raw string value on every change — convenience alternative to reading e.target.value from onChange */
|
|
39
|
+
onValueChange?: (value: string) => void;
|
|
38
40
|
}
|
|
39
41
|
export type TextareaSize = 'sm' | 'md' | 'lg';
|
|
40
42
|
export type TextareaState = 'default' | 'disabled' | 'invalid';
|
|
@@ -447,7 +447,7 @@ const TimePicker = React__default.forwardRef(({ value, defaultValue, onChange, f
|
|
|
447
447
|
else if (ref) {
|
|
448
448
|
ref.current = el;
|
|
449
449
|
}
|
|
450
|
-
}, className: cn(mergedTheme.containerStyle, className), children: [label && (jsx(FormLabel, { htmlFor: inputId, className: labelClassName, state: finalState, required: props.required, children: label })), jsx(TimePickerTrigger, { id: inputId, disabled: disabled, isOpen: isOpen, state: finalState, size: size, clearable: clearable, onClear: handleClear, iconStart: iconStart, iconEnd: iconEnd, inputValue: inputDisplayValue, onInputChange: handleInputChange, onInputFocus: handleInputFocus, onInputKeyDown: handleInputKeyDown, format: format, period: currentPeriod, onPeriodToggle: handlePeriodToggle, placeholder: placeholder }), jsxs(TimePickerContent, { isOpen: isOpen, onCancel: handleCancel, onSave: handleSave, portal: true, placement: "bottom-start", offset: 4, dropdownRef: dropdownRef, children: [jsx(WheelColumn, { label: "Hour", options: hourOptions, value: getDisplayHour(wheelTime.hour, format), onChange: handleHourChange, theme: mergedTheme }), jsx(WheelColumn, { label: "Min", options: minuteOptions, value: wheelTime.minute, onChange: handleMinuteChange, theme: mergedTheme }), format === "12h" && (jsx(WheelColumn, { label: "", options: periodOptions, value: wheelTime.period || "AM", onChange: handlePeriodChange, theme: mergedTheme }))] }), (helperText || validationError) && (jsx("p", { className: cn(mergedTheme.helperTextStyle, (_a = mergedTheme.helperTextStates) === null || _a === void 0 ? void 0 : _a[finalState], helperTextClassName), children: validationError || helperText }))] }) }));
|
|
450
|
+
}, className: cn(mergedTheme.containerStyle, className), children: [label && (typeof label === 'string' ? (jsx(FormLabel, { htmlFor: inputId, className: labelClassName, state: finalState, required: props.required, children: label })) : (label)), jsx(TimePickerTrigger, { id: inputId, disabled: disabled, isOpen: isOpen, state: finalState, size: size, clearable: clearable, onClear: handleClear, iconStart: iconStart, iconEnd: iconEnd, inputValue: inputDisplayValue, onInputChange: handleInputChange, onInputFocus: handleInputFocus, onInputKeyDown: handleInputKeyDown, format: format, period: currentPeriod, onPeriodToggle: handlePeriodToggle, placeholder: placeholder, "aria-invalid": finalState === 'invalid' || undefined, "aria-describedby": helperText ? `${inputId}-helper` : undefined }), jsxs(TimePickerContent, { isOpen: isOpen, onCancel: handleCancel, onSave: handleSave, portal: true, placement: "bottom-start", offset: 4, dropdownRef: dropdownRef, children: [jsx(WheelColumn, { label: "Hour", options: hourOptions, value: getDisplayHour(wheelTime.hour, format), onChange: handleHourChange, theme: mergedTheme }), jsx(WheelColumn, { label: "Min", options: minuteOptions, value: wheelTime.minute, onChange: handleMinuteChange, theme: mergedTheme }), format === "12h" && (jsx(WheelColumn, { label: "", options: periodOptions, value: wheelTime.period || "AM", onChange: handlePeriodChange, theme: mergedTheme }))] }), (helperText || validationError) && (typeof helperText === 'string' || validationError ? (jsx("p", { id: `${inputId}-helper`, className: cn(mergedTheme.helperTextStyle, (_a = mergedTheme.helperTextStates) === null || _a === void 0 ? void 0 : _a[finalState], helperTextClassName), children: validationError || helperText })) : (helperText))] }) }));
|
|
451
451
|
});
|
|
452
452
|
TimePicker.displayName = "TimePicker";
|
|
453
453
|
|
|
@@ -44,9 +44,9 @@ export interface TimePickerProps extends Omit<React.InputHTMLAttributes<HTMLInpu
|
|
|
44
44
|
/** Whether to show a clear button */
|
|
45
45
|
clearable?: boolean;
|
|
46
46
|
/** Optional label text */
|
|
47
|
-
label?:
|
|
47
|
+
label?: React.ReactNode;
|
|
48
48
|
/** Optional helper text */
|
|
49
|
-
helperText?:
|
|
49
|
+
helperText?: React.ReactNode;
|
|
50
50
|
/** Icon to display at the start (left side) */
|
|
51
51
|
iconStart?: React.ReactNode;
|
|
52
52
|
/** Icon to display at the end (right side) */
|
|
@@ -175,6 +175,10 @@ export interface TimePickerTriggerProps {
|
|
|
175
175
|
id?: string;
|
|
176
176
|
/** Whether the trigger is disabled */
|
|
177
177
|
disabled?: boolean;
|
|
178
|
+
/** Whether the trigger has an invalid value */
|
|
179
|
+
"aria-invalid"?: boolean;
|
|
180
|
+
/** ID of the element that describes the trigger */
|
|
181
|
+
"aria-describedby"?: string;
|
|
178
182
|
/** Whether the dropdown is open */
|
|
179
183
|
isOpen?: boolean;
|
|
180
184
|
/** Visual state of the trigger */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import { useContext, useCallback
|
|
2
|
+
import { useContext, useCallback } from 'react';
|
|
3
3
|
import { AnimatePresence, motion } from 'motion/react';
|
|
4
4
|
import { createPortal } from 'react-dom';
|
|
5
5
|
import { cn } from '../../../utils/cn.js';
|
|
@@ -93,35 +93,8 @@ import '../../core/ContextMenu/ContextMenu.theme.js';
|
|
|
93
93
|
import '../../core/Pill/Pill.js';
|
|
94
94
|
import '../../core/Icon/Icon.js';
|
|
95
95
|
import { useIsClient } from '../../../hooks/useIsClient.js';
|
|
96
|
+
import { useDarkMode } from '../../../hooks/useDarkMode.js';
|
|
96
97
|
|
|
97
|
-
/**
|
|
98
|
-
* Hook to detect dark mode state from document
|
|
99
|
-
*/
|
|
100
|
-
const useDarkMode = () => {
|
|
101
|
-
const [isDark, setIsDark] = useState(false);
|
|
102
|
-
useEffect(() => {
|
|
103
|
-
if (typeof document === "undefined")
|
|
104
|
-
return;
|
|
105
|
-
const checkDarkMode = () => {
|
|
106
|
-
const hasDarkClass = document.documentElement.classList.contains("dark") ||
|
|
107
|
-
document.body.classList.contains("dark") ||
|
|
108
|
-
document.querySelector(".dark") !== null;
|
|
109
|
-
setIsDark(hasDarkClass);
|
|
110
|
-
};
|
|
111
|
-
checkDarkMode();
|
|
112
|
-
const observer = new MutationObserver(checkDarkMode);
|
|
113
|
-
observer.observe(document.documentElement, {
|
|
114
|
-
attributes: true,
|
|
115
|
-
attributeFilter: ["class"],
|
|
116
|
-
});
|
|
117
|
-
observer.observe(document.body, {
|
|
118
|
-
attributes: true,
|
|
119
|
-
attributeFilter: ["class"],
|
|
120
|
-
});
|
|
121
|
-
return () => observer.disconnect();
|
|
122
|
-
}, []);
|
|
123
|
-
return isDark;
|
|
124
|
-
};
|
|
125
98
|
/**
|
|
126
99
|
* TimePickerContent Component - contains the time selector dropdown
|
|
127
100
|
* Uses portal positioning like Select and DatePicker components
|
|
@@ -9,7 +9,7 @@ import { TimePickerContext } from './TimePicker.js';
|
|
|
9
9
|
* Displays a masked time input that opens the wheel picker on focus
|
|
10
10
|
* Follows the same visual pattern as DatePickerTrigger and SelectButton
|
|
11
11
|
*/
|
|
12
|
-
const TimePickerTrigger = ({ id, disabled, isOpen, state = 'default', size = 'md', clearable, onClear, iconStart, iconEnd, className, inputValue, onInputChange, onInputFocus, onInputKeyDown, format, period, onPeriodToggle, placeholder, }) => {
|
|
12
|
+
const TimePickerTrigger = ({ id, disabled, isOpen, state = 'default', size = 'md', clearable, onClear, iconStart, iconEnd, className, inputValue, onInputChange, onInputFocus, onInputKeyDown, format, period, onPeriodToggle, placeholder, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedby, }) => {
|
|
13
13
|
var _a, _b, _c, _d;
|
|
14
14
|
const context = useContext(TimePickerContext);
|
|
15
15
|
if (!context) {
|
|
@@ -31,7 +31,7 @@ const TimePickerTrigger = ({ id, disabled, isOpen, state = 'default', size = 'md
|
|
|
31
31
|
const hasStartIcon = iconStart !== undefined ? Boolean(iconStart) : true;
|
|
32
32
|
const iconStartPadding = theme.iconStartPadding || "";
|
|
33
33
|
return (jsx("div", { ref: triggerRef, className: "relative w-full", children: jsxs("div", { className: cn(baseStyle, stateStyle, hoverStateStyle, activeFocusState, 'w-full items-center', className // User overrides take highest precedence
|
|
34
|
-
), children: [jsxs("div", { className: "relative flex-1", children: [jsx("input", { ref: inputRef, id: id, type: "text", inputMode: "numeric", value: inputValue, onChange: (e) => onInputChange(e.target.value), onFocus: onInputFocus, onKeyDown: onInputKeyDown, placeholder: placeholder, maxLength: 5, disabled: disabled, className: cn(inputStyle, sizeStyle, hasStartIcon && iconStartPadding), "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-label": "Enter time", autoComplete: "off" }), iconStart !== undefined ? (iconStart && jsx("div", { className: iconStartStyle, children: iconStart })) : (jsx("div", { className: iconStartStyle, children: jsx(ClockIcon, { className: "h-4 w-4" }) }))] }), format === '12h' && (jsx("button", { type: "button", onClick: onPeriodToggle, disabled: disabled, className: cn(periodToggleStyle, "shrink-0"), "aria-label": `Toggle AM/PM, current: ${period}`, tabIndex: -1, children: period || 'AM' })), clearable && hasValue && !disabled && (jsx("button", { type: "button", onClick: (e) => {
|
|
34
|
+
), children: [jsxs("div", { className: "relative flex-1", children: [jsx("input", { ref: inputRef, id: id, type: "text", inputMode: "numeric", value: inputValue, onChange: (e) => onInputChange(e.target.value), onFocus: onInputFocus, onKeyDown: onInputKeyDown, placeholder: placeholder, maxLength: 5, disabled: disabled, className: cn(inputStyle, sizeStyle, hasStartIcon && iconStartPadding), "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-label": "Enter time", "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, autoComplete: "off" }), iconStart !== undefined ? (iconStart && jsx("div", { className: iconStartStyle, children: iconStart })) : (jsx("div", { className: iconStartStyle, children: jsx(ClockIcon, { className: "h-4 w-4" }) }))] }), format === '12h' && (jsx("button", { type: "button", onClick: onPeriodToggle, disabled: disabled, className: cn(periodToggleStyle, "shrink-0"), "aria-label": `Toggle AM/PM, current: ${period}`, tabIndex: -1, children: period || 'AM' })), clearable && hasValue && !disabled && (jsx("button", { type: "button", onClick: (e) => {
|
|
35
35
|
e.stopPropagation();
|
|
36
36
|
onClear === null || onClear === void 0 ? void 0 : onClear();
|
|
37
37
|
}, className: "shrink-0 p-0.5 rounded text-[var(--color-text-muted)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-background-secondary)] transition-colors", "aria-label": "Clear time", tabIndex: -1, children: jsx(XMarkIcon, { className: "w-4 h-4" }) })), iconEnd !== undefined ? (iconEnd && (jsx("span", { className: "shrink-0 flex items-center pr-3 pointer-events-none text-[var(--color-text-muted)] dark:text-[var(--color-neutral-500)]", children: iconEnd }))) : (jsx("span", { className: "shrink-0 flex items-center pr-3 pointer-events-none text-[var(--color-text-muted)] dark:text-[var(--color-neutral-500)]", children: jsx(ChevronUpDownIcon, { className: "h-4 w-4" }) }))] }) }));
|
|
@@ -138,7 +138,7 @@ export { inputTagTheme } from './InputTag/InputTag.theme.js';
|
|
|
138
138
|
export { Combobox } from './Combobox/Combobox.js';
|
|
139
139
|
export { comboboxTheme } from './Combobox/Combobox.theme.js';
|
|
140
140
|
export { ColorPicker } from './ColorPicker/ColorPicker.js';
|
|
141
|
-
export {
|
|
141
|
+
export { useColorPicker } from './ColorPicker/ColorPickerContext.js';
|
|
142
142
|
export { ColorPickerTrigger } from './ColorPicker/ColorPickerTrigger.js';
|
|
143
143
|
export { ColorPickerBody } from './ColorPicker/ColorPickerBody.js';
|
|
144
144
|
export { ColorPicker2DCanvas } from './ColorPicker/ColorPicker2DCanvas.js';
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -14,3 +14,4 @@ export { useClickOutside } from "./useClickOutside";
|
|
|
14
14
|
export { useScaleBackground } from "./useScaleBackground";
|
|
15
15
|
export type { UseScaleBackgroundOptions } from "./useScaleBackground";
|
|
16
16
|
export { useMediaQuery } from "./useMediaQuery";
|
|
17
|
+
export { useDarkMode } from './useDarkMode';
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { RefObject } from 'react';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* @param handler The callback function to execute when a click outside is detected
|
|
3
|
+
* Overload 1 — legacy API: useClickOutside(ref, handler)
|
|
4
|
+
* Preserves backward compatibility with existing callers.
|
|
6
5
|
*/
|
|
7
|
-
export declare
|
|
6
|
+
export declare function useClickOutside<T extends HTMLElement | null>(ref: RefObject<T>, handler: (event: MouseEvent | TouchEvent) => void): void;
|
|
7
|
+
/**
|
|
8
|
+
* Overload 2 — new API: useClickOutside(callback, isActive?, additionalRefs?)
|
|
9
|
+
* Returns a ref to attach to the primary element.
|
|
10
|
+
* Accepts an optional array of additional refs whose contents count as "inside"
|
|
11
|
+
* (useful for trigger+content patterns).
|
|
12
|
+
*/
|
|
13
|
+
export declare function useClickOutside(callback: () => void, isActive?: boolean, additionalRefs?: RefObject<HTMLElement | null>[]): RefObject<HTMLElement | null>;
|
|
@@ -1,28 +1,48 @@
|
|
|
1
|
-
import { useRef, useEffect } from 'react';
|
|
1
|
+
import { useRef, useCallback, useEffect } from 'react';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
// Implementation
|
|
4
|
+
function useClickOutside(refOrCallback, handlerOrIsActive, additionalRefs) {
|
|
5
|
+
const internalRef = useRef(null);
|
|
6
|
+
const legacyHandlerRef = useRef(null);
|
|
7
|
+
// Keep legacy handler ref current
|
|
8
|
+
if (typeof refOrCallback !== 'function' && typeof handlerOrIsActive === 'function') {
|
|
9
|
+
legacyHandlerRef.current = handlerOrIsActive;
|
|
10
|
+
}
|
|
11
|
+
const isLegacy = typeof refOrCallback !== 'function';
|
|
12
|
+
const isActive = isLegacy
|
|
13
|
+
? true
|
|
14
|
+
: typeof handlerOrIsActive === 'boolean'
|
|
15
|
+
? handlerOrIsActive
|
|
16
|
+
: true;
|
|
17
|
+
const handleClickOutside = useCallback((event) => {
|
|
18
|
+
var _a;
|
|
19
|
+
const target = event.target;
|
|
20
|
+
if (isLegacy) {
|
|
21
|
+
const legacyRef = refOrCallback;
|
|
22
|
+
const el = legacyRef.current;
|
|
23
|
+
if (!el || el.contains(target))
|
|
24
|
+
return;
|
|
25
|
+
(_a = legacyHandlerRef.current) === null || _a === void 0 ? void 0 : _a.call(legacyHandlerRef, event);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
if (internalRef.current && internalRef.current.contains(target))
|
|
15
29
|
return;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
30
|
+
if (additionalRefs === null || additionalRefs === void 0 ? void 0 : additionalRefs.some(r => { var _a; return (_a = r.current) === null || _a === void 0 ? void 0 : _a.contains(target); }))
|
|
31
|
+
return;
|
|
32
|
+
refOrCallback();
|
|
33
|
+
}
|
|
34
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
35
|
+
}, [isLegacy, additionalRefs]);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (!isActive)
|
|
38
|
+
return;
|
|
39
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
40
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
41
|
+
}, [handleClickOutside, isActive]);
|
|
42
|
+
if (isLegacy) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
return internalRef;
|
|
46
|
+
}
|
|
27
47
|
|
|
28
48
|
export { useClickOutside };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function useDarkMode(): boolean;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
const _subscribers = new Set();
|
|
4
|
+
let _observer = null;
|
|
5
|
+
function _getIsDark() {
|
|
6
|
+
if (typeof document === 'undefined')
|
|
7
|
+
return false;
|
|
8
|
+
return (document.documentElement.classList.contains('dark') ||
|
|
9
|
+
document.body.classList.contains('dark') ||
|
|
10
|
+
document.querySelector('.dark') !== null);
|
|
11
|
+
}
|
|
12
|
+
function _ensureObserver() {
|
|
13
|
+
if (_observer || typeof document === 'undefined')
|
|
14
|
+
return;
|
|
15
|
+
_getIsDark();
|
|
16
|
+
_observer = new MutationObserver(() => {
|
|
17
|
+
_getIsDark();
|
|
18
|
+
_subscribers.forEach((fn) => fn());
|
|
19
|
+
});
|
|
20
|
+
_observer.observe(document.documentElement, {
|
|
21
|
+
attributes: true,
|
|
22
|
+
attributeFilter: ['class'],
|
|
23
|
+
});
|
|
24
|
+
_observer.observe(document.body, {
|
|
25
|
+
attributes: true,
|
|
26
|
+
attributeFilter: ['class'],
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function useDarkMode() {
|
|
30
|
+
const [, rerender] = useState(0);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
_ensureObserver();
|
|
33
|
+
const notify = () => rerender((n) => n + 1);
|
|
34
|
+
_subscribers.add(notify);
|
|
35
|
+
return () => {
|
|
36
|
+
_subscribers.delete(notify);
|
|
37
|
+
};
|
|
38
|
+
}, []);
|
|
39
|
+
return typeof document === 'undefined' ? false : _getIsDark();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { useDarkMode };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StateMachineConfig, StateIdentifier } from "../utils/stateMachine";
|
|
2
|
-
export interface UseFormStateMachineOptions<TData =
|
|
2
|
+
export interface UseFormStateMachineOptions<TData = unknown> {
|
|
3
3
|
/** Initial form data */
|
|
4
4
|
initialData?: TData;
|
|
5
5
|
/** Callback when state changes */
|
|
@@ -32,7 +32,7 @@ const getConnection = () => {
|
|
|
32
32
|
* }
|
|
33
33
|
*/
|
|
34
34
|
const useNetworkStatus = () => {
|
|
35
|
-
const [isOnline, setIsOnline] = useState(
|
|
35
|
+
const [isOnline, setIsOnline] = useState(true);
|
|
36
36
|
const [wasOffline, setWasOffline] = useState(false);
|
|
37
37
|
const [networkInfo, setNetworkInfo] = useState({});
|
|
38
38
|
const updateNetworkInfo = useCallback(() => {
|
package/dist/hooks/useOverlay.js
CHANGED
|
@@ -7,6 +7,8 @@ let lockCount = 0;
|
|
|
7
7
|
let savedOverflow = '';
|
|
8
8
|
let savedPaddingRight = '';
|
|
9
9
|
function lockScroll() {
|
|
10
|
+
if (typeof window === 'undefined')
|
|
11
|
+
return;
|
|
10
12
|
lockCount++;
|
|
11
13
|
if (lockCount === 1) {
|
|
12
14
|
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
|
@@ -23,6 +25,8 @@ function lockScroll() {
|
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
27
|
function unlockScroll() {
|
|
28
|
+
if (typeof window === 'undefined')
|
|
29
|
+
return;
|
|
26
30
|
lockCount = Math.max(0, lockCount - 1);
|
|
27
31
|
if (lockCount === 0) {
|
|
28
32
|
document.body.style.overflow = savedOverflow;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { useRef,
|
|
1
|
+
import { useRef, useEffect, useLayoutEffect } from 'react';
|
|
2
2
|
import { animate } from 'motion/react';
|
|
3
3
|
|
|
4
|
+
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
|
4
5
|
const WRAPPER_SELECTOR = "[data-flik-drawer-wrapper]";
|
|
5
6
|
/**
|
|
6
7
|
* useScaleBackground
|
|
@@ -22,7 +23,9 @@ function useScaleBackground({ isOpen, scale = 0.94, borderRadius = 24, position
|
|
|
22
23
|
const controlsRef = useRef(null);
|
|
23
24
|
// Track current animation progress so rapid toggling picks up where it left off
|
|
24
25
|
const progressRef = useRef(0);
|
|
25
|
-
|
|
26
|
+
useIsomorphicLayoutEffect(() => {
|
|
27
|
+
if (typeof window === 'undefined')
|
|
28
|
+
return;
|
|
26
29
|
// Skip if no scaling needed
|
|
27
30
|
if (scale >= 1)
|
|
28
31
|
return;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { useRef, useState, useCallback, useLayoutEffect } from 'react';
|
|
1
|
+
import { useRef, useState, useCallback, useLayoutEffect, useEffect } from 'react';
|
|
2
2
|
|
|
3
|
+
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
|
3
4
|
/**
|
|
4
5
|
* Fixed dropdown positioning hook
|
|
5
6
|
* Uses position: fixed with pure viewport coordinates to properly follow scroll
|
|
@@ -288,7 +289,9 @@ const useSimpleDropdown = ({ triggerRef, isOpen, placement = "bottom-start", off
|
|
|
288
289
|
contentRef.current.style.left = `${left}px`;
|
|
289
290
|
}, [triggerRef, measureDropdownHeight, measureDropdownWidth, offset]);
|
|
290
291
|
// Reset initial render flag when dropdown opens
|
|
291
|
-
|
|
292
|
+
useIsomorphicLayoutEffect(() => {
|
|
293
|
+
if (typeof window === 'undefined')
|
|
294
|
+
return;
|
|
292
295
|
if (!isOpen) {
|
|
293
296
|
if (rafIdRef.current !== null) {
|
|
294
297
|
cancelAnimationFrame(rafIdRef.current);
|
|
@@ -319,7 +322,9 @@ const useSimpleDropdown = ({ triggerRef, isOpen, placement = "bottom-start", off
|
|
|
319
322
|
};
|
|
320
323
|
}, [isOpen, calculatePosition]);
|
|
321
324
|
// Initial position calculation
|
|
322
|
-
|
|
325
|
+
useIsomorphicLayoutEffect(() => {
|
|
326
|
+
if (typeof window === 'undefined')
|
|
327
|
+
return;
|
|
323
328
|
if (!isOpen)
|
|
324
329
|
return;
|
|
325
330
|
calculatePosition();
|
|
@@ -363,7 +368,9 @@ const useSimpleDropdown = ({ triggerRef, isOpen, placement = "bottom-start", off
|
|
|
363
368
|
});
|
|
364
369
|
}, [calculatePosition]);
|
|
365
370
|
// Update position on scroll and resize - rAF-synced for smooth tracking
|
|
366
|
-
|
|
371
|
+
useIsomorphicLayoutEffect(() => {
|
|
372
|
+
if (typeof window === 'undefined')
|
|
373
|
+
return;
|
|
367
374
|
if (!isOpen)
|
|
368
375
|
return;
|
|
369
376
|
window.addEventListener("scroll", handleScroll, { passive: true, capture: true });
|
|
@@ -378,7 +385,9 @@ const useSimpleDropdown = ({ triggerRef, isOpen, placement = "bottom-start", off
|
|
|
378
385
|
};
|
|
379
386
|
}, [isOpen, handleScroll, handleResize]);
|
|
380
387
|
// Recalculate when dropdown content resizes (e.g. search filtering)
|
|
381
|
-
|
|
388
|
+
useIsomorphicLayoutEffect(() => {
|
|
389
|
+
if (typeof window === 'undefined')
|
|
390
|
+
return;
|
|
382
391
|
if (!isOpen)
|
|
383
392
|
return;
|
|
384
393
|
if (!contentRef.current)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
export * from "./components/core";
|
|
2
2
|
export * from "./components/data-display";
|
|
3
3
|
export * from "./components/forms";
|
|
4
|
-
export * from "./components/charts";
|
|
5
4
|
export * from "./components/layout";
|
|
6
|
-
export * from "./components/effects";
|
|
7
5
|
export { cn } from "./utils/cn";
|
|
8
6
|
export { debounce } from "./utils/debounce";
|
|
9
7
|
export { useClickOutside } from "./hooks/useClickOutside";
|