@loadsmart/loadsmart-ui 5.19.2 → 5.20.1
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/DatePicker/DatePicker.types.d.ts +3 -0
- package/dist/components/Dropdown/Dropdown.d.ts +2 -2
- package/dist/components/Dropdown/Dropdown.types.d.ts +5 -1
- package/dist/components/Popover/Popover.d.ts +9 -3
- package/dist/components/Popover/Popover.stories.d.ts +1 -1
- package/dist/components/Popover/Popover.types.d.ts +33 -0
- package/dist/components/Popover/index.d.ts +2 -2
- package/dist/components/TablePagination/RowsPerPage.d.ts +1 -1
- package/dist/components/TablePagination/TablePagination.types.d.ts +7 -1
- package/dist/components/Text/Text.d.ts +1 -1
- package/dist/components/Tooltip/Tooltip.d.ts +3 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +442 -481
- package/dist/index.js.map +1 -1
- package/dist/miranda-compatibility.theme-97e29e8e.js +2 -0
- package/dist/miranda-compatibility.theme-97e29e8e.js.map +1 -0
- package/dist/prop-5c502a5a.js +2 -0
- package/dist/{prop-a330029f.js.map → prop-5c502a5a.js.map} +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/theming/index.js +1 -1
- package/dist/theming/themes/alice.theme.d.ts +4 -0
- package/dist/theming/themes/loadsmart.theme.d.ts +4 -0
- package/dist/theming/themes/miranda-compatibility.theme.d.ts +4 -0
- package/dist/tools/index.js +1 -1
- package/package.json +3 -2
- package/src/components/DatePicker/DatePicker.tsx +8 -4
- package/src/components/DatePicker/DatePicker.types.ts +3 -0
- package/src/components/DatePicker/DateRangePicker.tsx +16 -12
- package/src/components/Dropdown/Dropdown.stories.tsx +41 -40
- package/src/components/Dropdown/Dropdown.tsx +35 -11
- package/src/components/Dropdown/Dropdown.types.ts +7 -1
- package/src/components/Dropdown/DropdownMenu.tsx +10 -14
- package/src/components/Dropdown/DropdownTrigger.tsx +8 -5
- package/src/components/Popover/Popover.stories.tsx +27 -4
- package/src/components/Popover/Popover.tsx +145 -13
- package/src/components/Popover/Popover.types.ts +41 -0
- package/src/components/Popover/index.ts +11 -2
- package/src/components/Select/Select.test.tsx +3 -3
- package/src/components/Select/SelectTrigger.tsx +18 -1
- package/src/components/Table/Table.stories.tsx +0 -1
- package/src/components/Table/Table.tsx +2 -2
- package/src/components/TablePagination/RowsPerPage.tsx +9 -4
- package/src/components/TablePagination/TablePagination.tsx +3 -0
- package/src/components/TablePagination/TablePagination.types.ts +12 -5
- package/src/components/Tooltip/Tooltip.tsx +59 -85
- package/src/components/TopNavigation/Menu/MenuItemDropdown.tsx +11 -8
- package/src/index.ts +10 -2
- package/src/testing/DatePickerEvent/DatePickerEvent.ts +2 -3
- package/src/testing/DatePickerEvent/DateRangePickerEvent.ts +1 -1
- package/src/testing/SelectEvent/SelectEvent.ts +3 -4
- package/src/theming/themes/alice.theme.ts +6 -0
- package/src/theming/themes/loadsmart.theme.ts +6 -0
- package/dist/miranda-compatibility.theme-4cecc6cf.js +0 -2
- package/dist/miranda-compatibility.theme-4cecc6cf.js.map +0 -1
- package/dist/prop-a330029f.js +0 -2
|
@@ -1,21 +1,153 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import
|
|
1
|
+
import React, { useMemo } from 'react'
|
|
2
|
+
import { useFloating, autoUpdate } from '@floating-ui/react-dom'
|
|
3
|
+
import { offset, flip, shift, arrow } from '@floating-ui/core'
|
|
4
|
+
import type { Placement, MiddlewareState } from '@floating-ui/core'
|
|
3
5
|
|
|
4
|
-
import {
|
|
6
|
+
import type {
|
|
7
|
+
PopoverAlign,
|
|
8
|
+
PopoverFloatingProps,
|
|
9
|
+
PopoverPosition,
|
|
10
|
+
PopoverProps,
|
|
11
|
+
PopoverReferenceProps,
|
|
12
|
+
UsePopoverReturn,
|
|
13
|
+
} from './Popover.types'
|
|
5
14
|
|
|
6
|
-
|
|
15
|
+
const PopoverContext = React.createContext<UsePopoverReturn | undefined>(undefined)
|
|
7
16
|
|
|
8
|
-
export
|
|
17
|
+
export function usePopover(): UsePopoverReturn {
|
|
18
|
+
const value = React.useContext(PopoverContext)
|
|
9
19
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
border-radius: ${token('popover-border-radius')};
|
|
14
|
-
box-shadow: ${token('popover-shadow')};
|
|
15
|
-
`
|
|
20
|
+
if (!value) {
|
|
21
|
+
throw new Error('usePopover must be used within a <Popover> Provider')
|
|
22
|
+
}
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
return <PopoverWrapper {...others}>{children}</PopoverWrapper>
|
|
24
|
+
return value
|
|
19
25
|
}
|
|
20
26
|
|
|
27
|
+
function Popover(props: PopoverProps): JSX.Element {
|
|
28
|
+
const arrowRef = React.useRef<HTMLElement | null>(null)
|
|
29
|
+
|
|
30
|
+
const { position = 'bottom', align = 'start', strategy = 'fixed' } = props
|
|
31
|
+
|
|
32
|
+
const desiredPlacement = `${position}${align === 'center' ? '' : `-${align}`}` as Placement
|
|
33
|
+
|
|
34
|
+
const result = useFloating({
|
|
35
|
+
placement: desiredPlacement,
|
|
36
|
+
strategy,
|
|
37
|
+
middleware: [
|
|
38
|
+
offset(10),
|
|
39
|
+
flip(),
|
|
40
|
+
shift(),
|
|
41
|
+
{
|
|
42
|
+
name: 'arrow',
|
|
43
|
+
fn(args: MiddlewareState) {
|
|
44
|
+
if (arrowRef.current) {
|
|
45
|
+
return arrow({ element: arrowRef.current, padding: 8 }).fn(args)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {}
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
// TODO: FloatingUI docs states that `autoUpdate` is expensive.
|
|
53
|
+
// This should be properly investidated since it's the way to
|
|
54
|
+
// update fixed positions after scrolling.
|
|
55
|
+
whileElementsMounted: autoUpdate,
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
const registerArrow = React.useCallback(
|
|
59
|
+
(node: HTMLElement) => {
|
|
60
|
+
arrowRef.current = node
|
|
61
|
+
result.update()
|
|
62
|
+
},
|
|
63
|
+
[result]
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
const [resultPosition = position, resultAlign = align] = result.placement.split('-') as [
|
|
67
|
+
PopoverPosition,
|
|
68
|
+
PopoverAlign
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
const value = useMemo(
|
|
72
|
+
() => ({
|
|
73
|
+
strategy,
|
|
74
|
+
register: {
|
|
75
|
+
reference: result.refs.setReference,
|
|
76
|
+
floating: result.refs.setFloating,
|
|
77
|
+
arrow: registerArrow,
|
|
78
|
+
},
|
|
79
|
+
result: {
|
|
80
|
+
floating: {
|
|
81
|
+
top: result.y ?? 0,
|
|
82
|
+
left: result.x ?? 0,
|
|
83
|
+
},
|
|
84
|
+
arrow: { top: result.middlewareData.arrow?.y, left: result.middlewareData.arrow?.x },
|
|
85
|
+
position: resultPosition,
|
|
86
|
+
align: resultAlign,
|
|
87
|
+
},
|
|
88
|
+
}),
|
|
89
|
+
[
|
|
90
|
+
registerArrow,
|
|
91
|
+
result.refs.setFloating,
|
|
92
|
+
result.middlewareData.arrow?.x,
|
|
93
|
+
result.middlewareData.arrow?.y,
|
|
94
|
+
result.refs.setReference,
|
|
95
|
+
result.x,
|
|
96
|
+
result.y,
|
|
97
|
+
resultAlign,
|
|
98
|
+
resultPosition,
|
|
99
|
+
strategy,
|
|
100
|
+
]
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
return <PopoverContext.Provider value={value}>{props.children}</PopoverContext.Provider>
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function PopoverReference({ children, ...others }: PopoverReferenceProps): JSX.Element {
|
|
107
|
+
const ref = React.useRef<HTMLDivElement | null>(null)
|
|
108
|
+
const { register } = usePopover()
|
|
109
|
+
|
|
110
|
+
React.useLayoutEffect(() => {
|
|
111
|
+
if (ref.current) {
|
|
112
|
+
register.reference(ref.current)
|
|
113
|
+
}
|
|
114
|
+
}, [register])
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<div ref={ref} {...others}>
|
|
118
|
+
{children}
|
|
119
|
+
</div>
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function PopoverFloating({ children, style, ...others }: PopoverFloatingProps): JSX.Element {
|
|
124
|
+
const { register, result, strategy } = usePopover()
|
|
125
|
+
|
|
126
|
+
const ref = React.useRef<HTMLDivElement | null>(null)
|
|
127
|
+
|
|
128
|
+
React.useLayoutEffect(() => {
|
|
129
|
+
if (ref.current) {
|
|
130
|
+
register.floating(ref.current)
|
|
131
|
+
}
|
|
132
|
+
}, [register])
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
<div
|
|
136
|
+
ref={ref}
|
|
137
|
+
{...others}
|
|
138
|
+
style={{
|
|
139
|
+
position: strategy,
|
|
140
|
+
top: result.floating.top,
|
|
141
|
+
left: result.floating.left,
|
|
142
|
+
...style,
|
|
143
|
+
}}
|
|
144
|
+
>
|
|
145
|
+
{children}
|
|
146
|
+
</div>
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
Popover.Floating = PopoverFloating
|
|
151
|
+
Popover.Reference = PopoverReference
|
|
152
|
+
|
|
21
153
|
export default Popover
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { HTMLAttributes, MutableRefObject, PropsWithChildren } from 'react'
|
|
2
|
+
|
|
3
|
+
export interface UsePopoverReturn {
|
|
4
|
+
register: {
|
|
5
|
+
reference: (el: HTMLElement) => void
|
|
6
|
+
floating: (el: HTMLElement) => void
|
|
7
|
+
arrow: (el: HTMLElement) => void
|
|
8
|
+
}
|
|
9
|
+
result: {
|
|
10
|
+
floating: {
|
|
11
|
+
top: number
|
|
12
|
+
left: number
|
|
13
|
+
}
|
|
14
|
+
arrow: {
|
|
15
|
+
top: number | undefined
|
|
16
|
+
left: number | undefined
|
|
17
|
+
}
|
|
18
|
+
position: PopoverPosition
|
|
19
|
+
align: PopoverAlign
|
|
20
|
+
}
|
|
21
|
+
strategy: 'fixed' | 'absolute'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type PopoverPosition = 'top' | 'bottom' | 'right' | 'left'
|
|
25
|
+
export type PopoverAlign = 'start' | 'center' | 'end'
|
|
26
|
+
|
|
27
|
+
export interface PopoverPlacement {
|
|
28
|
+
position?: PopoverPosition
|
|
29
|
+
align?: PopoverAlign
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type PopoverProps = PropsWithChildren<
|
|
33
|
+
PopoverPlacement & {
|
|
34
|
+
strategy?: UsePopoverReturn['strategy']
|
|
35
|
+
arrow?: MutableRefObject<HTMLElement | null>
|
|
36
|
+
}
|
|
37
|
+
>
|
|
38
|
+
|
|
39
|
+
export type PopoverReferenceProps = HTMLAttributes<HTMLDivElement>
|
|
40
|
+
|
|
41
|
+
export type PopoverFloatingProps = HTMLAttributes<HTMLDivElement>
|
|
@@ -1,2 +1,11 @@
|
|
|
1
|
-
export { default as Popover } from './Popover'
|
|
2
|
-
|
|
1
|
+
export { default as Popover, usePopover } from './Popover'
|
|
2
|
+
|
|
3
|
+
export type {
|
|
4
|
+
PopoverProps,
|
|
5
|
+
PopoverFloatingProps,
|
|
6
|
+
PopoverReferenceProps,
|
|
7
|
+
PopoverPlacement,
|
|
8
|
+
PopoverPosition,
|
|
9
|
+
PopoverAlign,
|
|
10
|
+
UsePopoverReturn,
|
|
11
|
+
} from './Popover.types'
|
|
@@ -341,7 +341,7 @@ describe('Select', () => {
|
|
|
341
341
|
|
|
342
342
|
expect(firstSelection).toHaveTextContent(firstOption.label)
|
|
343
343
|
expect(secondSelection).toHaveTextContent(secondOption.label)
|
|
344
|
-
})
|
|
344
|
+
}, 30_000)
|
|
345
345
|
|
|
346
346
|
it('unselects a selected option keeping selected the others', async () => {
|
|
347
347
|
const [firstOption, secondOption, thirdOption] = generator.pickset([...FRUITS], 3)
|
|
@@ -525,7 +525,7 @@ describe('Select', () => {
|
|
|
525
525
|
const optionText = getOptionText(option)
|
|
526
526
|
expect(selectedOptions[index]).toHaveTextContent(optionText)
|
|
527
527
|
}
|
|
528
|
-
})
|
|
528
|
+
}, 30_000)
|
|
529
529
|
|
|
530
530
|
it.each([[{ multiple: true }], [{ multiple: false }]])(
|
|
531
531
|
'overrides the empty component with %s',
|
|
@@ -1037,6 +1037,6 @@ describe('Select', () => {
|
|
|
1037
1037
|
|
|
1038
1038
|
await selectEvent.expand(searchInput)
|
|
1039
1039
|
expect(screen.getByText('No more options.')).toBeInTheDocument()
|
|
1040
|
-
})
|
|
1040
|
+
}, 30_000)
|
|
1041
1041
|
})
|
|
1042
1042
|
})
|
|
@@ -7,6 +7,8 @@ import { TextField, Trailing } from 'components/TextField'
|
|
|
7
7
|
import focusable from 'styles/focusable'
|
|
8
8
|
|
|
9
9
|
import type { SelectTriggerProps } from './Select.types'
|
|
10
|
+
import { isFunction } from '@loadsmart/utils-function'
|
|
11
|
+
import { usePopover } from 'components/Popover'
|
|
10
12
|
|
|
11
13
|
const GenericSelectTrigger = styled(GenericDropdownTrigger)`
|
|
12
14
|
background: ${token('color-neutral-white')};
|
|
@@ -47,6 +49,15 @@ const SelectTrigger = forwardRef<HTMLInputElement, SelectTriggerProps>(function
|
|
|
47
49
|
) {
|
|
48
50
|
const { className, ...others } = props
|
|
49
51
|
const { disabled, expanded, toggle } = useContext(DropdownContext)
|
|
52
|
+
const triggerRef = React.useRef<HTMLElement | null>(null)
|
|
53
|
+
|
|
54
|
+
const { register } = usePopover()
|
|
55
|
+
|
|
56
|
+
React.useEffect(() => {
|
|
57
|
+
if (triggerRef.current) {
|
|
58
|
+
register.reference(triggerRef.current)
|
|
59
|
+
}
|
|
60
|
+
}, [register])
|
|
50
61
|
|
|
51
62
|
function handleClick() {
|
|
52
63
|
if (!expanded) {
|
|
@@ -59,7 +70,13 @@ const SelectTrigger = forwardRef<HTMLInputElement, SelectTriggerProps>(function
|
|
|
59
70
|
<SelectTriggerSearchField
|
|
60
71
|
data-testid="select-trigger-search-field"
|
|
61
72
|
{...others}
|
|
62
|
-
ref={
|
|
73
|
+
ref={(node) => {
|
|
74
|
+
if (isFunction(ref)) {
|
|
75
|
+
ref(node)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
triggerRef.current = node
|
|
79
|
+
}}
|
|
63
80
|
type="search"
|
|
64
81
|
disabled={disabled}
|
|
65
82
|
onClick={handleClick}
|
|
@@ -12,7 +12,6 @@ import type { RowFixture } from './Table.fixtures'
|
|
|
12
12
|
import { Button } from 'components/Button'
|
|
13
13
|
import { Text } from 'components/Text'
|
|
14
14
|
import { Switch } from 'components/Switch'
|
|
15
|
-
import { Icon } from 'components/Icon'
|
|
16
15
|
|
|
17
16
|
export default {
|
|
18
17
|
title: 'Components/Table',
|
|
@@ -451,7 +451,7 @@ function TablePicker<T>({
|
|
|
451
451
|
...props
|
|
452
452
|
}: TablePickerProps<T>): JSX.Element {
|
|
453
453
|
return (
|
|
454
|
-
<Dropdown>
|
|
454
|
+
<Dropdown align={align}>
|
|
455
455
|
<StyledPickerTrigger trailing={null} scale="small" {...props}>
|
|
456
456
|
{propsTrigger !== undefined ? (
|
|
457
457
|
({ expanded }) => (isFunction(propsTrigger) ? propsTrigger(expanded) : propsTrigger)
|
|
@@ -459,7 +459,7 @@ function TablePicker<T>({
|
|
|
459
459
|
<TriggerIcon />
|
|
460
460
|
)}
|
|
461
461
|
</StyledPickerTrigger>
|
|
462
|
-
<Dropdown.Menu
|
|
462
|
+
<Dropdown.Menu role="listbox">
|
|
463
463
|
{children ||
|
|
464
464
|
options?.map((option, i) => (
|
|
465
465
|
<TablePickerItem
|
|
@@ -6,14 +6,17 @@ import { Icon } from 'components/Icon'
|
|
|
6
6
|
import type { RowsPerPageProps } from './TablePagination.types'
|
|
7
7
|
import type { ButtonProps } from 'components/Button'
|
|
8
8
|
import { NoPaddingButton } from './TablePagination.styles'
|
|
9
|
+
import { Popover } from 'components/Popover'
|
|
9
10
|
|
|
10
11
|
const TriggerButton = (props: Omit<ButtonProps, 'scale' | 'variant'>) => {
|
|
11
12
|
const { toggle } = React.useContext(DropdownContext)
|
|
12
13
|
|
|
13
14
|
return (
|
|
14
|
-
<
|
|
15
|
-
<
|
|
16
|
-
|
|
15
|
+
<Popover.Reference>
|
|
16
|
+
<NoPaddingButton data-testid="rows-per-page-button" onClick={toggle} {...props}>
|
|
17
|
+
<Icon name="caret-down" size={16} color="neutral-darker" />
|
|
18
|
+
</NoPaddingButton>
|
|
19
|
+
</Popover.Reference>
|
|
17
20
|
)
|
|
18
21
|
}
|
|
19
22
|
|
|
@@ -25,6 +28,8 @@ function RowsPerPage({
|
|
|
25
28
|
count,
|
|
26
29
|
rowsPerPageOptions,
|
|
27
30
|
disabled = false,
|
|
31
|
+
position = 'bottom',
|
|
32
|
+
align = 'start',
|
|
28
33
|
}: RowsPerPageProps): JSX.Element {
|
|
29
34
|
const getItemsRange = () => {
|
|
30
35
|
if (!count) {
|
|
@@ -55,7 +60,7 @@ function RowsPerPage({
|
|
|
55
60
|
{count}
|
|
56
61
|
</Text>
|
|
57
62
|
</Text>
|
|
58
|
-
<Dropdown>
|
|
63
|
+
<Dropdown position={position} align={align}>
|
|
59
64
|
<TriggerButton disabled={disabled} />
|
|
60
65
|
<Dropdown.Menu>
|
|
61
66
|
{rowsPerPageOptions.map((option) => (
|
|
@@ -17,6 +17,7 @@ function TablePagination(props: TablePaginationProps): JSX.Element {
|
|
|
17
17
|
rowsPerPage = 50,
|
|
18
18
|
rowsPerPageOptions = [10, 25, 50, 100],
|
|
19
19
|
disabled = false,
|
|
20
|
+
rowsPerPagePlacement,
|
|
20
21
|
...rest
|
|
21
22
|
} = props
|
|
22
23
|
|
|
@@ -30,6 +31,8 @@ function TablePagination(props: TablePaginationProps): JSX.Element {
|
|
|
30
31
|
rowsPerPageOptions={rowsPerPageOptions}
|
|
31
32
|
labelRowsPerPage={labelRowsPerPage}
|
|
32
33
|
disabled={disabled || !count}
|
|
34
|
+
position={rowsPerPagePlacement?.position}
|
|
35
|
+
align={rowsPerPagePlacement?.align}
|
|
33
36
|
/>
|
|
34
37
|
<TablePaginationActions
|
|
35
38
|
variant={variant}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { GroupProps } from 'components/Layout/Group'
|
|
2
|
+
import type { PopoverPlacement } from 'components/Popover'
|
|
2
3
|
|
|
3
4
|
export interface TablePaginationProps extends GroupProps {
|
|
4
5
|
/**
|
|
@@ -44,6 +45,11 @@ export interface TablePaginationProps extends GroupProps {
|
|
|
44
45
|
* Disable all the pagination actions
|
|
45
46
|
*/
|
|
46
47
|
disabled?: boolean
|
|
48
|
+
/**
|
|
49
|
+
* Customizes the placement of the rows per page select field.
|
|
50
|
+
* @default { position: 'bottom', align: 'start' }
|
|
51
|
+
*/
|
|
52
|
+
rowsPerPagePlacement?: PopoverPlacement
|
|
47
53
|
}
|
|
48
54
|
|
|
49
55
|
export type TablePaginationActionsProps = Omit<
|
|
@@ -55,8 +61,9 @@ export type TablePaginationActionsProps = Omit<
|
|
|
55
61
|
|
|
56
62
|
export type RowsPerPageProps = Omit<
|
|
57
63
|
TablePaginationProps,
|
|
58
|
-
'rowsPerPageOptions' | 'onPageChange' | 'rowsPerPage'
|
|
59
|
-
> &
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
'rowsPerPageOptions' | 'onPageChange' | 'rowsPerPage' | 'align'
|
|
65
|
+
> &
|
|
66
|
+
PopoverPlacement & {
|
|
67
|
+
rowsPerPageOptions: number[]
|
|
68
|
+
rowsPerPage: number
|
|
69
|
+
}
|
|
@@ -4,10 +4,12 @@ import styled, { css } from 'styled-components'
|
|
|
4
4
|
|
|
5
5
|
import type ColorScheme from 'utils/types/ColorScheme'
|
|
6
6
|
import focusable from 'styles/focusable'
|
|
7
|
-
import transition from 'styles/transition'
|
|
8
|
-
import font from 'styles/font'
|
|
9
7
|
import conditional, { whenProps } from 'tools/conditional'
|
|
10
8
|
import { getToken as token } from 'theming'
|
|
9
|
+
import { Popover, usePopover } from 'components/Popover'
|
|
10
|
+
import typography from 'styles/typography'
|
|
11
|
+
|
|
12
|
+
import type { PopoverAlign, PopoverPosition } from 'components/Popover'
|
|
11
13
|
|
|
12
14
|
export enum TooltipPosition {
|
|
13
15
|
Top = 'top',
|
|
@@ -25,8 +27,8 @@ export enum TooltipAlign {
|
|
|
25
27
|
export interface TooltipProps extends HTMLAttributes<HTMLDivElement> {
|
|
26
28
|
message: ReactNode
|
|
27
29
|
scheme?: ColorScheme
|
|
28
|
-
position?: TooltipPosition
|
|
29
|
-
align?: TooltipAlign
|
|
30
|
+
position?: TooltipPosition | PopoverPosition
|
|
31
|
+
align?: TooltipAlign | PopoverAlign
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
type ContainerProps = Pick<TooltipProps, 'scheme'>
|
|
@@ -46,15 +48,8 @@ const Container = styled.div<ContainerProps>`
|
|
|
46
48
|
`}
|
|
47
49
|
`
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const Bubble = styled.span<BubbleProps>`
|
|
52
|
-
${font({
|
|
53
|
-
weight: 'font-weight-medium',
|
|
54
|
-
height: 'font-height-3',
|
|
55
|
-
})}
|
|
56
|
-
|
|
57
|
-
${transition()}
|
|
51
|
+
const Bubble = styled.div`
|
|
52
|
+
${typography('body')}
|
|
58
53
|
|
|
59
54
|
white-space: initial;
|
|
60
55
|
|
|
@@ -62,7 +57,6 @@ const Bubble = styled.span<BubbleProps>`
|
|
|
62
57
|
max-width: ${token('tooltip-max-width')};
|
|
63
58
|
width: max-content;
|
|
64
59
|
|
|
65
|
-
position: absolute;
|
|
66
60
|
z-index: ${token('z-index-tooltip')};
|
|
67
61
|
|
|
68
62
|
background: ${token('tooltip-background')};
|
|
@@ -74,108 +68,85 @@ const Bubble = styled.span<BubbleProps>`
|
|
|
74
68
|
color: ${token('tooltip-color')};
|
|
75
69
|
font-size: ${token('tooltip-font-size')};
|
|
76
70
|
line-height: ${token('tooltip-font-height')};
|
|
71
|
+
`
|
|
77
72
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
left: 50%;
|
|
83
|
-
|
|
84
|
-
transform: ${conditional({
|
|
85
|
-
'translate(-10%, -100%)': whenProps({ align: TooltipAlign.Start }),
|
|
86
|
-
'translate(-50%, -100%)': whenProps({ align: TooltipAlign.Center }),
|
|
87
|
-
'translate(-90%, -100%)': whenProps({ align: TooltipAlign.End }),
|
|
88
|
-
})};
|
|
89
|
-
`}
|
|
90
|
-
|
|
91
|
-
${({ position }) =>
|
|
92
|
-
position === TooltipPosition.Bottom &&
|
|
93
|
-
css`
|
|
94
|
-
bottom: -16px;
|
|
95
|
-
left: 50%;
|
|
96
|
-
|
|
97
|
-
transform: ${conditional({
|
|
98
|
-
'translate(-10%, 100%)': whenProps({ align: TooltipAlign.Start }),
|
|
99
|
-
'translate(-50%, 100%)': whenProps({ align: TooltipAlign.Center }),
|
|
100
|
-
'translate(-90%, 100%)': whenProps({ align: TooltipAlign.End }),
|
|
101
|
-
})};
|
|
102
|
-
`};
|
|
103
|
-
|
|
104
|
-
${({ position }) =>
|
|
105
|
-
position === TooltipPosition.Left &&
|
|
106
|
-
css`
|
|
107
|
-
top: 50%;
|
|
108
|
-
left: -16px;
|
|
109
|
-
|
|
110
|
-
transform: translate(-100%, -50%);
|
|
111
|
-
`};
|
|
112
|
-
|
|
113
|
-
${({ position }) =>
|
|
114
|
-
position === TooltipPosition.Right &&
|
|
115
|
-
css`
|
|
116
|
-
top: 50%;
|
|
117
|
-
right: -16px;
|
|
73
|
+
type ArrowProps = Pick<TooltipProps, 'position'> & {
|
|
74
|
+
top?: number
|
|
75
|
+
left?: number
|
|
76
|
+
}
|
|
118
77
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
`
|
|
78
|
+
const StyledArrow = styled.span<ArrowProps>`
|
|
79
|
+
position: absolute;
|
|
122
80
|
|
|
123
|
-
type ArrowProps = Pick<TooltipProps, 'position'>
|
|
124
|
-
const Arrow = styled.span<ArrowProps>`
|
|
125
81
|
width: 0;
|
|
126
82
|
height: 0;
|
|
83
|
+
display: block;
|
|
127
84
|
|
|
128
85
|
background: transparent;
|
|
129
86
|
border-style: solid;
|
|
130
87
|
|
|
131
|
-
position: absolute;
|
|
132
88
|
z-index: 1;
|
|
133
89
|
|
|
90
|
+
${({ top }) => top && `top: ${top}px;`}
|
|
91
|
+
${({ left }) => left && `left: ${left}px;`}
|
|
92
|
+
|
|
134
93
|
${({ position }) =>
|
|
135
|
-
position ===
|
|
94
|
+
position === 'top' &&
|
|
136
95
|
css`
|
|
137
|
-
bottom:
|
|
138
|
-
left: 50%;
|
|
96
|
+
bottom: -8px;
|
|
139
97
|
|
|
140
98
|
border-color: ${token('tooltip-background')} transparent transparent transparent;
|
|
141
99
|
border-width: 12px 10px 0 10px;
|
|
142
|
-
transform: translate(-50%, -100%);
|
|
143
100
|
`}
|
|
144
101
|
|
|
145
102
|
${({ position }) =>
|
|
146
|
-
position ===
|
|
103
|
+
position === 'bottom' &&
|
|
147
104
|
css`
|
|
148
|
-
top:
|
|
149
|
-
left: 50%;
|
|
105
|
+
top: -8px;
|
|
150
106
|
|
|
151
107
|
border-color: transparent transparent ${token('tooltip-background')} transparent;
|
|
152
108
|
border-width: 0 10px 12px 10px;
|
|
153
|
-
transform: translate(-50%, 100%);
|
|
154
109
|
`}
|
|
155
110
|
|
|
156
111
|
${({ position }) =>
|
|
157
|
-
position ===
|
|
112
|
+
position === 'left' &&
|
|
158
113
|
css`
|
|
159
|
-
|
|
160
|
-
right: calc(100% - 4px);
|
|
114
|
+
right: -8px;
|
|
161
115
|
|
|
162
116
|
border-color: transparent transparent transparent ${token('tooltip-background')};
|
|
163
117
|
border-width: 10px 0 10px 12px;
|
|
164
|
-
transform: translate(-100%, -50%);
|
|
165
118
|
`}
|
|
166
119
|
|
|
167
120
|
${({ position }) =>
|
|
168
|
-
position ===
|
|
121
|
+
position === 'right' &&
|
|
169
122
|
css`
|
|
170
|
-
|
|
171
|
-
left: calc(100% - 4px);
|
|
123
|
+
left: -8px;
|
|
172
124
|
|
|
173
125
|
border-color: transparent ${token('tooltip-background')} transparent transparent;
|
|
174
126
|
border-width: 10px 12px 10px 0;
|
|
175
|
-
transform: translate(100%, -50%);
|
|
176
127
|
`}
|
|
177
128
|
`
|
|
178
129
|
|
|
130
|
+
function Arrow() {
|
|
131
|
+
const { register, result } = usePopover()
|
|
132
|
+
const ref = React.useRef<HTMLDivElement | null>(null)
|
|
133
|
+
|
|
134
|
+
React.useLayoutEffect(() => {
|
|
135
|
+
if (ref.current) {
|
|
136
|
+
register.arrow(ref.current)
|
|
137
|
+
}
|
|
138
|
+
}, [register])
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<StyledArrow
|
|
142
|
+
ref={ref}
|
|
143
|
+
position={result.position}
|
|
144
|
+
top={result.arrow.top}
|
|
145
|
+
left={result.arrow.left}
|
|
146
|
+
/>
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
|
|
179
150
|
function Tooltip({
|
|
180
151
|
children,
|
|
181
152
|
message,
|
|
@@ -204,15 +175,18 @@ function Tooltip({
|
|
|
204
175
|
tabIndex={0}
|
|
205
176
|
scheme={scheme}
|
|
206
177
|
>
|
|
207
|
-
{
|
|
208
|
-
|
|
209
|
-
<
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
178
|
+
<Popover position={position} align={align}>
|
|
179
|
+
{visible && (
|
|
180
|
+
<Popover.Floating>
|
|
181
|
+
<Bubble role="tooltip">
|
|
182
|
+
{message}
|
|
183
|
+
<Arrow />
|
|
184
|
+
</Bubble>
|
|
185
|
+
</Popover.Floating>
|
|
186
|
+
)}
|
|
187
|
+
|
|
188
|
+
<Popover.Reference>{children}</Popover.Reference>
|
|
189
|
+
</Popover>
|
|
216
190
|
</Container>
|
|
217
191
|
)
|
|
218
192
|
}
|
|
@@ -11,6 +11,7 @@ import { BaseLink } from 'components/Link'
|
|
|
11
11
|
import useID from 'hooks/useID'
|
|
12
12
|
import ellipsizable from 'styles/ellipsizable'
|
|
13
13
|
import typography from 'styles/typography'
|
|
14
|
+
import { Popover } from 'components/Popover'
|
|
14
15
|
|
|
15
16
|
export const MenuDropdown = styled(Dropdown)({})
|
|
16
17
|
|
|
@@ -96,14 +97,16 @@ function MenuItemDropdown(props: MenuItemDropdownProps): JSX.Element {
|
|
|
96
97
|
const labelId = useID()
|
|
97
98
|
|
|
98
99
|
return (
|
|
99
|
-
<MenuDropdown key={label}>
|
|
100
|
-
<
|
|
101
|
-
<
|
|
102
|
-
{
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
100
|
+
<MenuDropdown align="end" key={label}>
|
|
101
|
+
<Popover.Reference>
|
|
102
|
+
<MenuDropdownLabel>
|
|
103
|
+
<Ellipsizable $max={120} id={labelId}>
|
|
104
|
+
{label}
|
|
105
|
+
</Ellipsizable>
|
|
106
|
+
<MenuDropdownTrigger {...rest} tabIndex={0} aria-labelledby={labelId} />
|
|
107
|
+
</MenuDropdownLabel>
|
|
108
|
+
</Popover.Reference>
|
|
109
|
+
<DropdownMenu>{children}</DropdownMenu>
|
|
107
110
|
</MenuDropdown>
|
|
108
111
|
)
|
|
109
112
|
}
|
package/src/index.ts
CHANGED
|
@@ -83,8 +83,16 @@ export type { CardProps } from './components/Card'
|
|
|
83
83
|
export { IconFactory } from './components/IconFactory'
|
|
84
84
|
export type { IconProps, IconMapping } from './components/IconFactory'
|
|
85
85
|
|
|
86
|
-
export { Popover } from './components/Popover'
|
|
87
|
-
export type {
|
|
86
|
+
export { Popover, usePopover } from './components/Popover'
|
|
87
|
+
export type {
|
|
88
|
+
PopoverProps,
|
|
89
|
+
PopoverAlign,
|
|
90
|
+
PopoverPosition,
|
|
91
|
+
PopoverFloatingProps,
|
|
92
|
+
PopoverPlacement,
|
|
93
|
+
PopoverReferenceProps,
|
|
94
|
+
UsePopoverReturn,
|
|
95
|
+
} from './components/Popover'
|
|
88
96
|
|
|
89
97
|
export { Dropdown, useDropdown, DropdownContext } from './components/Dropdown'
|
|
90
98
|
export type { DropdownProps, useDropdownProps } from './components/Dropdown'
|