@udixio/ui-react 2.9.13 → 2.9.15
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/CHANGELOG.md +40 -0
- package/dist/index.cjs +3 -3
- package/dist/index.js +4348 -3781
- package/dist/lib/components/AnchorPositioner.d.ts +11 -0
- package/dist/lib/components/AnchorPositioner.d.ts.map +1 -0
- package/dist/lib/components/Button.d.ts.map +1 -1
- package/dist/lib/components/Card.d.ts +2 -2
- package/dist/lib/components/Card.d.ts.map +1 -1
- package/dist/lib/components/Checkbox.d.ts +15 -0
- package/dist/lib/components/Checkbox.d.ts.map +1 -0
- package/dist/lib/components/DatePicker.d.ts +9 -0
- package/dist/lib/components/DatePicker.d.ts.map +1 -0
- package/dist/lib/components/FabMenu.d.ts.map +1 -1
- package/dist/lib/components/IconButton.d.ts.map +1 -1
- package/dist/lib/components/TabGroup.d.ts +1 -0
- package/dist/lib/components/TabGroup.d.ts.map +1 -1
- package/dist/lib/components/TabGroupContext.d.ts +1 -0
- package/dist/lib/components/TabGroupContext.d.ts.map +1 -1
- package/dist/lib/components/TabPanel.d.ts +1 -0
- package/dist/lib/components/TabPanel.d.ts.map +1 -1
- package/dist/lib/components/TabPanels.d.ts +1 -0
- package/dist/lib/components/TabPanels.d.ts.map +1 -1
- package/dist/lib/components/TextField.d.ts +4 -5
- package/dist/lib/components/TextField.d.ts.map +1 -1
- package/dist/lib/components/Tooltip.d.ts +1 -1
- package/dist/lib/components/Tooltip.d.ts.map +1 -1
- package/dist/lib/components/index.d.ts +3 -0
- package/dist/lib/components/index.d.ts.map +1 -1
- package/dist/lib/effects/State.d.ts +3 -1
- package/dist/lib/effects/State.d.ts.map +1 -1
- package/dist/lib/effects/smooth-scroll.effect.d.ts +14 -0
- package/dist/lib/effects/smooth-scroll.effect.d.ts.map +1 -1
- package/dist/lib/hooks/index.d.ts +0 -1
- package/dist/lib/hooks/index.d.ts.map +1 -1
- package/dist/lib/interfaces/card.interface.d.ts +1 -1
- package/dist/lib/interfaces/card.interface.d.ts.map +1 -1
- package/dist/lib/interfaces/checkbox.interface.d.ts +38 -0
- package/dist/lib/interfaces/checkbox.interface.d.ts.map +1 -0
- package/dist/lib/interfaces/date-picker.interface.d.ts +67 -0
- package/dist/lib/interfaces/date-picker.interface.d.ts.map +1 -0
- package/dist/lib/interfaces/icon-button.interface.d.ts +2 -1
- package/dist/lib/interfaces/icon-button.interface.d.ts.map +1 -1
- package/dist/lib/interfaces/index.d.ts +1 -0
- package/dist/lib/interfaces/index.d.ts.map +1 -1
- package/dist/lib/interfaces/text-field.interface.d.ts +8 -5
- package/dist/lib/interfaces/text-field.interface.d.ts.map +1 -1
- package/dist/lib/interfaces/tooltip.interface.d.ts +2 -0
- package/dist/lib/interfaces/tooltip.interface.d.ts.map +1 -1
- package/dist/lib/styles/card.style.d.ts +5 -5
- package/dist/lib/styles/checkbox.style.d.ts +45 -0
- package/dist/lib/styles/checkbox.style.d.ts.map +1 -0
- package/dist/lib/styles/date-picker.style.d.ts +45 -0
- package/dist/lib/styles/date-picker.style.d.ts.map +1 -0
- package/dist/lib/styles/fab.style.d.ts +2 -2
- package/dist/lib/styles/icon-button.style.d.ts +10 -4
- package/dist/lib/styles/icon-button.style.d.ts.map +1 -1
- package/dist/lib/styles/index.d.ts +1 -0
- package/dist/lib/styles/index.d.ts.map +1 -1
- package/dist/lib/styles/navigation-rail-item.style.d.ts +2 -2
- package/dist/lib/styles/side-sheet.style.d.ts +2 -2
- package/dist/lib/styles/slider.style.d.ts +2 -2
- package/dist/lib/styles/tab.style.d.ts +2 -2
- package/dist/lib/styles/text-field.style.d.ts +22 -13
- package/dist/lib/styles/text-field.style.d.ts.map +1 -1
- package/dist/lib/styles/tooltip.style.d.ts +8 -4
- package/dist/lib/styles/tooltip.style.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/lib/components/AnchorPositioner.tsx +132 -0
- package/src/lib/components/Button.tsx +1 -0
- package/src/lib/components/Card.tsx +9 -4
- package/src/lib/components/Checkbox.tsx +120 -0
- package/src/lib/components/DatePicker.tsx +432 -0
- package/src/lib/components/FabMenu.tsx +4 -5
- package/src/lib/components/IconButton.tsx +9 -7
- package/src/lib/components/TabGroup.tsx +8 -6
- package/src/lib/components/TabGroupContext.tsx +1 -1
- package/src/lib/components/TabPanel.tsx +1 -0
- package/src/lib/components/TabPanels.tsx +1 -0
- package/src/lib/components/TextField.tsx +222 -123
- package/src/lib/components/Tooltip.tsx +13 -13
- package/src/lib/components/index.ts +3 -0
- package/src/lib/effects/State.tsx +4 -1
- package/src/lib/effects/smooth-scroll.effect.tsx +15 -1
- package/src/lib/hooks/index.ts +0 -1
- package/src/lib/interfaces/card.interface.ts +1 -1
- package/src/lib/interfaces/checkbox.interface.ts +39 -0
- package/src/lib/interfaces/date-picker.interface.ts +79 -0
- package/src/lib/interfaces/icon-button.interface.ts +2 -1
- package/src/lib/interfaces/index.ts +1 -0
- package/src/lib/interfaces/text-field.interface.ts +8 -5
- package/src/lib/interfaces/tooltip.interface.ts +2 -0
- package/src/lib/styles/checkbox.style.ts +64 -0
- package/src/lib/styles/date-picker.style.ts +43 -0
- package/src/lib/styles/index.ts +1 -0
- package/src/lib/styles/side-sheet.style.ts +2 -2
- package/src/lib/styles/text-field.style.ts +2 -2
- package/src/stories/containment/card.stories.tsx +1 -1
- package/dist/lib/hooks/useTooltipPosition.d.ts +0 -22
- package/dist/lib/hooks/useTooltipPosition.d.ts.map +0 -1
- package/src/lib/hooks/useTooltipPosition.ts +0 -95
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
type Props = {
|
|
4
|
+
checked?: boolean;
|
|
5
|
+
defaultChecked?: boolean;
|
|
6
|
+
indeterminate?: boolean;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
error?: boolean;
|
|
9
|
+
onChange?: React.ChangeEventHandler<HTMLInputElement>;
|
|
10
|
+
name?: string;
|
|
11
|
+
id?: string;
|
|
12
|
+
value?: string;
|
|
13
|
+
style?: React.CSSProperties;
|
|
14
|
+
className?: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type CheckboxStates = {
|
|
18
|
+
isChecked: boolean;
|
|
19
|
+
isIndeterminate: boolean;
|
|
20
|
+
isDisabled: boolean;
|
|
21
|
+
isError: boolean;
|
|
22
|
+
isFocused: boolean;
|
|
23
|
+
isHovered: boolean;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export interface CheckboxInterface {
|
|
27
|
+
type: 'div';
|
|
28
|
+
props: Props;
|
|
29
|
+
states: CheckboxStates;
|
|
30
|
+
elements: [
|
|
31
|
+
'checkbox',
|
|
32
|
+
'input',
|
|
33
|
+
'container',
|
|
34
|
+
'box',
|
|
35
|
+
'icon',
|
|
36
|
+
'stateLayer',
|
|
37
|
+
'ripple',
|
|
38
|
+
];
|
|
39
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
export type DateRange = [Date | null, Date | null];
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
/**
|
|
7
|
+
* Selection mode: 'single' for one date, 'range' for start/end period.
|
|
8
|
+
* @default 'single'
|
|
9
|
+
*/
|
|
10
|
+
mode?: 'single' | 'range';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The currently selected date(s).
|
|
14
|
+
* Date for single mode, [start, end] tuple for range mode.
|
|
15
|
+
*/
|
|
16
|
+
value?: Date | DateRange | null;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Default selected date(s) for uncontrolled usage.
|
|
20
|
+
*/
|
|
21
|
+
defaultValue?: Date | DateRange | null;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Callback fired when selection changes.
|
|
25
|
+
* Returns Date in single mode, DateRange in range mode.
|
|
26
|
+
*/
|
|
27
|
+
onChange?: (value: any) => void;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Minimum selectable date.
|
|
31
|
+
*/
|
|
32
|
+
minDate?: Date;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Maximum selectable date.
|
|
36
|
+
*/
|
|
37
|
+
maxDate?: Date;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Disables specific dates.
|
|
41
|
+
*/
|
|
42
|
+
shouldDisableDate?: (date: Date) => boolean;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Locale for formatting dates.
|
|
46
|
+
*/
|
|
47
|
+
locale?: string;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* First day of the week (0=Sunday, 1=Monday).
|
|
51
|
+
* @default 0
|
|
52
|
+
*/
|
|
53
|
+
weekStartDay?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
54
|
+
|
|
55
|
+
className?: string;
|
|
56
|
+
style?: React.CSSProperties;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export type DatePickerStates = {
|
|
60
|
+
// Can be expanded if we need specific state-driven styles exposed to the config
|
|
61
|
+
hasSelected: boolean;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export interface DatePickerInterface {
|
|
65
|
+
type: 'div';
|
|
66
|
+
props: Props;
|
|
67
|
+
states: DatePickerStates;
|
|
68
|
+
elements: [
|
|
69
|
+
'datePicker',
|
|
70
|
+
'header',
|
|
71
|
+
'monthNav',
|
|
72
|
+
'monthLabel',
|
|
73
|
+
'weekDays',
|
|
74
|
+
'weekDay',
|
|
75
|
+
'daysGrid',
|
|
76
|
+
'dayCell',
|
|
77
|
+
'dayButton', // The interactive part of the day
|
|
78
|
+
];
|
|
79
|
+
}
|
|
@@ -7,7 +7,7 @@ import { Icon } from '../icon';
|
|
|
7
7
|
type Props = {
|
|
8
8
|
label?: string;
|
|
9
9
|
children?: string;
|
|
10
|
-
icon
|
|
10
|
+
icon?: Icon;
|
|
11
11
|
size?: 'xSmall' | 'small' | 'medium' | 'large' | 'xLarge';
|
|
12
12
|
width?: 'default' | 'narrow' | 'wide';
|
|
13
13
|
iconSelected?: IconDefinition;
|
|
@@ -15,6 +15,7 @@ type Props = {
|
|
|
15
15
|
variant?: IconButtonVariant;
|
|
16
16
|
disabled?: boolean;
|
|
17
17
|
activated?: boolean;
|
|
18
|
+
title?: string | null;
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* The shape of the button defines whether it is squared or rounded.
|
|
@@ -2,6 +2,7 @@ export * from './button.interface';
|
|
|
2
2
|
export * from './card.interface';
|
|
3
3
|
export * from './carousel-item.interface';
|
|
4
4
|
export * from './carousel.interface';
|
|
5
|
+
export * from './checkbox.interface';
|
|
5
6
|
export * from './chip.interface';
|
|
6
7
|
export * from './chips.interface';
|
|
7
8
|
export * from './divider.interface';
|
|
@@ -6,22 +6,25 @@ export type TextFieldVariant = 'filled' | 'outlined';
|
|
|
6
6
|
|
|
7
7
|
type Props = {
|
|
8
8
|
placeholder?: string;
|
|
9
|
-
name
|
|
9
|
+
name?: string;
|
|
10
10
|
label: string;
|
|
11
11
|
disabled?: boolean;
|
|
12
12
|
errorText?: string | null;
|
|
13
13
|
supportingText?: string;
|
|
14
14
|
trailingIcon?: React.ReactElement<typeof IconButton> | Icon;
|
|
15
15
|
leadingIcon?: React.ReactElement<typeof IconButton> | Icon;
|
|
16
|
-
onChange?:
|
|
16
|
+
onChange?: React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>;
|
|
17
17
|
showSupportingText?: boolean;
|
|
18
18
|
suffix?: string;
|
|
19
19
|
|
|
20
|
-
value
|
|
20
|
+
value?: string;
|
|
21
|
+
defaultValue?: string;
|
|
22
|
+
id?: string;
|
|
23
|
+
style?: React.CSSProperties;
|
|
21
24
|
variant?: TextFieldVariant;
|
|
22
|
-
type?: 'text' | 'password' | 'number';
|
|
25
|
+
type?: 'text' | 'password' | 'number' | 'date';
|
|
23
26
|
autoComplete?: 'on' | 'off' | string;
|
|
24
|
-
|
|
27
|
+
multiline?: boolean;
|
|
25
28
|
};
|
|
26
29
|
export type TextFieldStates = {
|
|
27
30
|
isFocused: boolean;
|
|
@@ -38,6 +38,8 @@ export type ToolTipInterface<T extends HTMLElement = any> = {
|
|
|
38
38
|
onOpenChange?: (open: boolean) => void;
|
|
39
39
|
/** Custom ID for accessibility linking. Auto-generated if not provided. */
|
|
40
40
|
id?: string;
|
|
41
|
+
/** Custom anchor for positioning. Defaults to the trigger element. */
|
|
42
|
+
anchorRef?: RefObject<HTMLElement>;
|
|
41
43
|
} & (
|
|
42
44
|
| {
|
|
43
45
|
children?: never;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ClassNameComponent,
|
|
3
|
+
classNames,
|
|
4
|
+
createUseClassNames,
|
|
5
|
+
defaultClassNames,
|
|
6
|
+
} from '../utils';
|
|
7
|
+
import { CheckboxInterface } from '../interfaces/checkbox.interface';
|
|
8
|
+
|
|
9
|
+
const checkboxConfig: ClassNameComponent<CheckboxInterface> = ({
|
|
10
|
+
isChecked,
|
|
11
|
+
isIndeterminate,
|
|
12
|
+
isDisabled,
|
|
13
|
+
isError,
|
|
14
|
+
isFocused,
|
|
15
|
+
isHovered,
|
|
16
|
+
}) => ({
|
|
17
|
+
checkbox: classNames(
|
|
18
|
+
'inline-flex items-center justify-center relative size-4.5 ',
|
|
19
|
+
{
|
|
20
|
+
'pointer-events-none opacity-[0.38]': isDisabled,
|
|
21
|
+
},
|
|
22
|
+
),
|
|
23
|
+
input: classNames(
|
|
24
|
+
'absolute inset-0 w-full h-full opacity-0 z-10 cursor-pointer',
|
|
25
|
+
),
|
|
26
|
+
container: classNames(
|
|
27
|
+
'relative flex items-center justify-center w-[18px] h-[18px] ',
|
|
28
|
+
),
|
|
29
|
+
box: classNames(
|
|
30
|
+
'absolute left-1/2 top-1/2 -translate-1/2 to rounded-[2px] size-4 border-2 transition-colors duration-200',
|
|
31
|
+
// Unchecked state (Border only)
|
|
32
|
+
!isChecked &&
|
|
33
|
+
!isIndeterminate && {
|
|
34
|
+
'border-on-surface-variant': !isError && !isDisabled,
|
|
35
|
+
'border-error': isError && !isDisabled,
|
|
36
|
+
'border-on-surface': isDisabled,
|
|
37
|
+
},
|
|
38
|
+
// Checked or Indeterminate state (Filled)
|
|
39
|
+
(isChecked || isIndeterminate) && {
|
|
40
|
+
'bg-primary border-primary': !isError && !isDisabled,
|
|
41
|
+
'bg-error border-error': isError && !isDisabled,
|
|
42
|
+
'bg-on-surface border-on-surface': isDisabled,
|
|
43
|
+
},
|
|
44
|
+
),
|
|
45
|
+
icon: classNames(
|
|
46
|
+
'z-10 relative text-on-primary w-full h-full flex items-center justify-center pointer-events-none',
|
|
47
|
+
{
|
|
48
|
+
'text-on-error': isError && !isDisabled,
|
|
49
|
+
'text-surface': isDisabled, // Usually on-surface with opacity against on-surface bg? No, checked disabled is on-surface bg with surface icon usually.
|
|
50
|
+
},
|
|
51
|
+
),
|
|
52
|
+
stateLayer:
|
|
53
|
+
'size-10 state-ripple-group-[checkbox] rounded-full cursor-pointer pointer-events-auto absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2',
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export const checkboxStyle = defaultClassNames<CheckboxInterface>(
|
|
57
|
+
'checkbox',
|
|
58
|
+
checkboxConfig,
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
export const useCheckboxStyle = createUseClassNames<CheckboxInterface>(
|
|
62
|
+
'checkbox',
|
|
63
|
+
checkboxConfig,
|
|
64
|
+
);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ClassNameComponent,
|
|
3
|
+
classNames,
|
|
4
|
+
createUseClassNames,
|
|
5
|
+
defaultClassNames,
|
|
6
|
+
} from '../utils';
|
|
7
|
+
import { DatePickerInterface } from '../interfaces/date-picker.interface';
|
|
8
|
+
|
|
9
|
+
const datePickerConfig: ClassNameComponent<DatePickerInterface> = ({
|
|
10
|
+
hasSelected,
|
|
11
|
+
}) => ({
|
|
12
|
+
datePicker: classNames(
|
|
13
|
+
'inline-flex flex-col bg-surface-container-high rounded-[28px] p-3 select-none', // Using shadow-sm as placeholder for elevation
|
|
14
|
+
'min-w-[320px]',
|
|
15
|
+
),
|
|
16
|
+
header: classNames('flex items-center justify-between h-12 mb-2 px-2'),
|
|
17
|
+
monthNav: classNames(
|
|
18
|
+
'flex items-center justify-center w-10 h-10 rounded-full text-on-surface-variant hover:bg-on-surface-variant/8 transition-colors cursor-pointer',
|
|
19
|
+
),
|
|
20
|
+
monthLabel: classNames(
|
|
21
|
+
'text-label-large text-on-surface font-bold capitalize',
|
|
22
|
+
),
|
|
23
|
+
weekDays: classNames('grid grid-cols-7 mb-2'),
|
|
24
|
+
weekDay: classNames(
|
|
25
|
+
'h-10 flex items-center justify-center text-body-small text-on-surface-variant',
|
|
26
|
+
),
|
|
27
|
+
daysGrid: classNames('grid grid-cols-7 row-auto gap-y-2'),
|
|
28
|
+
dayCell: classNames('flex items-center justify-center h-10 p-0 relative'),
|
|
29
|
+
dayButton: classNames(
|
|
30
|
+
'w-10 h-10 rounded-full flex items-center justify-center text-body-large transition-all duration-200 relative overflow-hidden z-10 outline-none',
|
|
31
|
+
// Base style is implicit text-on-surface
|
|
32
|
+
),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export const datePickerStyle = defaultClassNames<DatePickerInterface>(
|
|
36
|
+
'datePicker',
|
|
37
|
+
datePickerConfig,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
export const useDatePickerStyle = createUseClassNames<DatePickerInterface>(
|
|
41
|
+
'datePicker',
|
|
42
|
+
datePickerConfig,
|
|
43
|
+
);
|
package/src/lib/styles/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from './button.style';
|
|
|
2
2
|
export * from './card.style';
|
|
3
3
|
export * from './carousel-item.style';
|
|
4
4
|
export * from './carousel.style';
|
|
5
|
+
export * from './checkbox.style';
|
|
5
6
|
export * from './chip.style';
|
|
6
7
|
export * from './chips.style';
|
|
7
8
|
export * from './divider.style';
|
|
@@ -25,9 +25,9 @@ export const sideSheetConfig: ClassNameComponent<SideSheetInterface> = ({
|
|
|
25
25
|
},
|
|
26
26
|
],
|
|
27
27
|
),
|
|
28
|
-
container: classNames('w-full overflow-hidden', {}),
|
|
29
|
-
content: classNames('w-fit '),
|
|
28
|
+
container: classNames('w-full overflow-hidden flex flex-col', {}),
|
|
30
29
|
header: classNames('p-4 flex items-center gap-2'),
|
|
30
|
+
content: classNames('flex-1 overflow-y-auto'),
|
|
31
31
|
title: classNames('text-on-surface-variant text-title-large'),
|
|
32
32
|
closeButton: classNames('ml-auto'),
|
|
33
33
|
divider: classNames({ hidden: variant == 'modal' }),
|
|
@@ -16,14 +16,14 @@ const textFieldConfig: ClassNameComponent<TextFieldInterface> = ({
|
|
|
16
16
|
isFocused,
|
|
17
17
|
value,
|
|
18
18
|
suffix,
|
|
19
|
-
|
|
19
|
+
multiline,
|
|
20
20
|
}) => ({
|
|
21
21
|
textField: classNames({
|
|
22
22
|
'opacity-[.38]': disabled,
|
|
23
23
|
}),
|
|
24
24
|
content: classNames(
|
|
25
25
|
'group/text-field transition-border duration-200 relative flex items-center ',
|
|
26
|
-
{ 'h-14':
|
|
26
|
+
{ 'h-14': !multiline },
|
|
27
27
|
{
|
|
28
28
|
'border-on-surface-variant':
|
|
29
29
|
!errorText?.length && !isFocused && variant == 'filled',
|
|
@@ -25,7 +25,7 @@ const createCardStory = (variant: ReactProps<CardInterface>['variant']) => {
|
|
|
25
25
|
<Card className={'w-[360px] h-[360px]'} {...args}></Card>
|
|
26
26
|
<a className={'group'} href={'https://example.com/'} target={'_blank'}>
|
|
27
27
|
<Card
|
|
28
|
-
|
|
28
|
+
interactive={true}
|
|
29
29
|
className={'w-[360px] h-[360px]'}
|
|
30
30
|
{...args}
|
|
31
31
|
></Card>
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { RefObject } from 'react';
|
|
2
|
-
type Position = 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
3
|
-
type Variant = 'plain' | 'rich';
|
|
4
|
-
export interface UseTooltipPositionOptions {
|
|
5
|
-
targetRef: RefObject<HTMLElement | null>;
|
|
6
|
-
position?: Position;
|
|
7
|
-
variant?: Variant;
|
|
8
|
-
isOpen: boolean;
|
|
9
|
-
}
|
|
10
|
-
export interface UseTooltipPositionReturn {
|
|
11
|
-
resolvedPosition: Position;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Hook to calculate tooltip position using useLayoutEffect.
|
|
15
|
-
* Auto-flips position if not enough viewport space.
|
|
16
|
-
*
|
|
17
|
-
* For plain variant: prefers left/right, falls back to top/bottom
|
|
18
|
-
* For rich variant: uses corner positions (top-left, top-right, bottom-left, bottom-right)
|
|
19
|
-
*/
|
|
20
|
-
export declare function useTooltipPosition({ targetRef, position: positionProp, variant, isOpen, }: UseTooltipPositionOptions): UseTooltipPositionReturn;
|
|
21
|
-
export {};
|
|
22
|
-
//# sourceMappingURL=useTooltipPosition.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useTooltipPosition.d.ts","sourceRoot":"","sources":["../../../src/lib/hooks/useTooltipPosition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAA6B,MAAM,OAAO,CAAC;AAE7D,KAAK,QAAQ,GACT,KAAK,GACL,QAAQ,GACR,MAAM,GACN,OAAO,GACP,UAAU,GACV,WAAW,GACX,aAAa,GACb,cAAc,CAAC;AAEnB,KAAK,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAEhC,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACzC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,gBAAgB,EAAE,QAAQ,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,SAAS,EACT,QAAQ,EAAE,YAAY,EACtB,OAAiB,EACjB,MAAM,GACP,EAAE,yBAAyB,GAAG,wBAAwB,CAyDtD"}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { RefObject, useLayoutEffect, useState } from 'react';
|
|
2
|
-
|
|
3
|
-
type Position =
|
|
4
|
-
| 'top'
|
|
5
|
-
| 'bottom'
|
|
6
|
-
| 'left'
|
|
7
|
-
| 'right'
|
|
8
|
-
| 'top-left'
|
|
9
|
-
| 'top-right'
|
|
10
|
-
| 'bottom-left'
|
|
11
|
-
| 'bottom-right';
|
|
12
|
-
|
|
13
|
-
type Variant = 'plain' | 'rich';
|
|
14
|
-
|
|
15
|
-
export interface UseTooltipPositionOptions {
|
|
16
|
-
targetRef: RefObject<HTMLElement | null>;
|
|
17
|
-
position?: Position;
|
|
18
|
-
variant?: Variant;
|
|
19
|
-
isOpen: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface UseTooltipPositionReturn {
|
|
23
|
-
resolvedPosition: Position;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Hook to calculate tooltip position using useLayoutEffect.
|
|
28
|
-
* Auto-flips position if not enough viewport space.
|
|
29
|
-
*
|
|
30
|
-
* For plain variant: prefers left/right, falls back to top/bottom
|
|
31
|
-
* For rich variant: uses corner positions (top-left, top-right, bottom-left, bottom-right)
|
|
32
|
-
*/
|
|
33
|
-
export function useTooltipPosition({
|
|
34
|
-
targetRef,
|
|
35
|
-
position: positionProp,
|
|
36
|
-
variant = 'plain',
|
|
37
|
-
isOpen,
|
|
38
|
-
}: UseTooltipPositionOptions): UseTooltipPositionReturn {
|
|
39
|
-
const [resolvedPosition, setResolvedPosition] = useState<Position>(
|
|
40
|
-
positionProp ?? 'bottom',
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
useLayoutEffect(() => {
|
|
44
|
-
// If position is explicitly set, use it
|
|
45
|
-
if (positionProp) {
|
|
46
|
-
setResolvedPosition(positionProp);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Only calculate if open and we have a target
|
|
51
|
-
if (!isOpen || !targetRef.current || typeof window === 'undefined') {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const targetElement = targetRef.current;
|
|
56
|
-
const rect = targetElement.getBoundingClientRect();
|
|
57
|
-
|
|
58
|
-
const viewportWidth = window.innerWidth;
|
|
59
|
-
const viewportHeight = window.innerHeight;
|
|
60
|
-
|
|
61
|
-
// Normalized position (0-1 range)
|
|
62
|
-
const x = rect.left / viewportWidth;
|
|
63
|
-
const y = rect.top / viewportHeight;
|
|
64
|
-
|
|
65
|
-
let newPosition: Position;
|
|
66
|
-
|
|
67
|
-
if (variant === 'plain') {
|
|
68
|
-
// Plain variant: prefer horizontal positioning, fall back to vertical
|
|
69
|
-
if (x < 1 / 3) {
|
|
70
|
-
newPosition = 'right';
|
|
71
|
-
} else if (x > 2 / 3) {
|
|
72
|
-
newPosition = 'left';
|
|
73
|
-
} else {
|
|
74
|
-
newPosition = y > 0.5 ? 'top' : 'bottom';
|
|
75
|
-
}
|
|
76
|
-
} else {
|
|
77
|
-
// Rich variant: use corner positions
|
|
78
|
-
if (x < 0.5 && y < 0.5) {
|
|
79
|
-
newPosition = 'bottom-right';
|
|
80
|
-
} else if (x >= 0.5 && y < 0.5) {
|
|
81
|
-
newPosition = 'bottom-left';
|
|
82
|
-
} else if (x >= 0.5 && y >= 0.5) {
|
|
83
|
-
newPosition = 'top-left';
|
|
84
|
-
} else {
|
|
85
|
-
newPosition = 'top-right';
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
setResolvedPosition(newPosition);
|
|
90
|
-
}, [isOpen, targetRef, positionProp, variant]);
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
resolvedPosition,
|
|
94
|
-
};
|
|
95
|
-
}
|