@duro-app/ui 4.2.0 → 4.3.0
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/DetailPanel/DetailPanel.meta.d.ts.map +1 -1
- package/dist/components/Dialog/Dialog.meta.d.ts.map +1 -1
- package/dist/components/Drawer/Drawer.meta.d.ts.map +1 -1
- package/dist/components/Menu/Menu.meta.d.ts.map +1 -1
- package/dist/components/Popover/Popover.d.ts +41 -0
- package/dist/components/Popover/Popover.d.ts.map +1 -0
- package/dist/components/Popover/Popover.meta.d.ts +3 -0
- package/dist/components/Popover/Popover.meta.d.ts.map +1 -0
- package/dist/components/Popover/Popover.stories.d.ts +11 -0
- package/dist/components/Popover/Popover.stories.d.ts.map +1 -0
- package/dist/components/Popover/outside.d.ts +2 -0
- package/dist/components/Popover/outside.d.ts.map +1 -0
- package/dist/components/Popover/position.d.ts +27 -0
- package/dist/components/Popover/position.d.ts.map +1 -0
- package/dist/components/Popover/styles.css.d.ts +61 -0
- package/dist/components/Popover/styles.css.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1645 -1381
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/DetailPanel/DetailPanel.meta.ts +6 -0
- package/src/components/Dialog/Dialog.meta.ts +6 -0
- package/src/components/Drawer/Drawer.meta.ts +6 -0
- package/src/components/Menu/Menu.meta.ts +5 -1
- package/src/components/Popover/Popover.meta.ts +69 -0
- package/src/components/Popover/Popover.stories.tsx +250 -0
- package/src/components/Popover/Popover.tsx +293 -0
- package/src/components/Popover/outside.ts +9 -0
- package/src/components/Popover/position.ts +48 -0
- package/src/components/Popover/styles.css.ts +75 -0
- package/src/components/Tooltip/Tooltip.meta.ts +1 -1
- package/src/index.ts +2 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface PopoverRect {
|
|
2
|
+
top: number
|
|
3
|
+
left: number
|
|
4
|
+
width: number
|
|
5
|
+
height: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface PopoverSize {
|
|
9
|
+
width: number
|
|
10
|
+
height: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type PopoverSide = 'top' | 'bottom'
|
|
14
|
+
export type PopoverAlign = 'start' | 'center' | 'end'
|
|
15
|
+
|
|
16
|
+
interface Input {
|
|
17
|
+
anchor: PopoverRect
|
|
18
|
+
popup: PopoverSize
|
|
19
|
+
viewport: PopoverSize
|
|
20
|
+
side: PopoverSide
|
|
21
|
+
align: PopoverAlign
|
|
22
|
+
offset: number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Pure placement: puts the popup on the requested side of the anchor, flips to
|
|
26
|
+
// the opposite side when it would overflow the viewport there (and the other
|
|
27
|
+
// side fits), and clamps horizontally into the viewport.
|
|
28
|
+
export function computePopoverPosition({anchor, popup, viewport, side, align, offset}: Input) {
|
|
29
|
+
const below = anchor.top + anchor.height + offset
|
|
30
|
+
const above = anchor.top - offset - popup.height
|
|
31
|
+
const fitsBelow = below + popup.height <= viewport.height
|
|
32
|
+
const fitsAbove = above >= 0
|
|
33
|
+
|
|
34
|
+
let resolved: PopoverSide = side
|
|
35
|
+
if (side === 'bottom' && !fitsBelow && fitsAbove) resolved = 'top'
|
|
36
|
+
else if (side === 'top' && !fitsAbove && fitsBelow) resolved = 'bottom'
|
|
37
|
+
|
|
38
|
+
const top = resolved === 'bottom' ? below : above
|
|
39
|
+
|
|
40
|
+
let left = anchor.left
|
|
41
|
+
if (align === 'center') left = anchor.left + (anchor.width - popup.width) / 2
|
|
42
|
+
else if (align === 'end') left = anchor.left + anchor.width - popup.width
|
|
43
|
+
|
|
44
|
+
const maxLeft = Math.max(0, viewport.width - popup.width)
|
|
45
|
+
left = Math.min(Math.max(0, left), maxLeft)
|
|
46
|
+
|
|
47
|
+
return {top, left, side: resolved}
|
|
48
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {css} from 'react-strict-dom'
|
|
2
|
+
import {colors} from '@duro-app/tokens/tokens/colors.css'
|
|
3
|
+
import {spacing, radii} from '@duro-app/tokens/tokens/spacing.css'
|
|
4
|
+
import {typography} from '@duro-app/tokens/tokens/typography.css'
|
|
5
|
+
import {shadows} from '@duro-app/tokens/tokens/shadows.css'
|
|
6
|
+
import {duration} from '@duro-app/tokens/tokens/motion.css'
|
|
7
|
+
|
|
8
|
+
export const styles = css.create({
|
|
9
|
+
trigger: {
|
|
10
|
+
display: 'inline-flex',
|
|
11
|
+
alignItems: 'center',
|
|
12
|
+
gap: spacing.sm,
|
|
13
|
+
paddingTop: spacing.sm,
|
|
14
|
+
paddingBottom: spacing.sm,
|
|
15
|
+
paddingLeft: spacing.md,
|
|
16
|
+
paddingRight: spacing.md,
|
|
17
|
+
fontFamily: typography.fontFamily,
|
|
18
|
+
fontSize: typography.fontSizeSm,
|
|
19
|
+
color: colors.text,
|
|
20
|
+
backgroundColor: {
|
|
21
|
+
default: 'transparent',
|
|
22
|
+
':hover': colors.bgCardHover,
|
|
23
|
+
},
|
|
24
|
+
borderWidth: 1,
|
|
25
|
+
borderStyle: 'solid',
|
|
26
|
+
borderColor: colors.border,
|
|
27
|
+
borderRadius: radii.sm,
|
|
28
|
+
cursor: 'pointer',
|
|
29
|
+
transitionProperty: 'background-color, border-color',
|
|
30
|
+
transitionDuration: duration.fast,
|
|
31
|
+
},
|
|
32
|
+
popup: {
|
|
33
|
+
position: 'fixed',
|
|
34
|
+
top: 0,
|
|
35
|
+
left: 0,
|
|
36
|
+
boxSizing: 'border-box',
|
|
37
|
+
backgroundColor: colors.bgCard,
|
|
38
|
+
borderWidth: 1,
|
|
39
|
+
borderStyle: 'solid',
|
|
40
|
+
borderColor: colors.border,
|
|
41
|
+
borderRadius: radii.sm,
|
|
42
|
+
boxShadow: shadows.md,
|
|
43
|
+
padding: spacing.md,
|
|
44
|
+
fontFamily: typography.fontFamily,
|
|
45
|
+
fontSize: typography.fontSizeSm,
|
|
46
|
+
color: colors.text,
|
|
47
|
+
zIndex: 50,
|
|
48
|
+
// The portal layer is pointer-events: none so clicks fall through it;
|
|
49
|
+
// the popup takes them back.
|
|
50
|
+
pointerEvents: 'auto',
|
|
51
|
+
},
|
|
52
|
+
close: {
|
|
53
|
+
display: 'inline-flex',
|
|
54
|
+
alignItems: 'center',
|
|
55
|
+
paddingTop: spacing.xs,
|
|
56
|
+
paddingBottom: spacing.xs,
|
|
57
|
+
paddingLeft: spacing.sm,
|
|
58
|
+
paddingRight: spacing.sm,
|
|
59
|
+
fontFamily: typography.fontFamily,
|
|
60
|
+
fontSize: typography.fontSizeSm,
|
|
61
|
+
color: colors.text,
|
|
62
|
+
backgroundColor: {
|
|
63
|
+
default: 'transparent',
|
|
64
|
+
':hover': colors.bgCardHover,
|
|
65
|
+
},
|
|
66
|
+
borderWidth: 0,
|
|
67
|
+
borderRadius: radii.sm,
|
|
68
|
+
cursor: 'pointer',
|
|
69
|
+
},
|
|
70
|
+
// Dynamic position — applied at runtime from the measured anchor.
|
|
71
|
+
popupPosition: (top: number, left: number) => ({
|
|
72
|
+
top,
|
|
73
|
+
left,
|
|
74
|
+
}),
|
|
75
|
+
})
|
|
@@ -9,7 +9,7 @@ export const meta: ComponentMeta = {
|
|
|
9
9
|
],
|
|
10
10
|
whenNotToUse: [
|
|
11
11
|
'Critical information that must always be visible — use Text or Callout',
|
|
12
|
-
'Interactive content (links, buttons) — tooltips are not interactive',
|
|
12
|
+
'Interactive content (links, buttons) — tooltips are not interactive — use Popover',
|
|
13
13
|
],
|
|
14
14
|
anatomy: {
|
|
15
15
|
required: ['Root', 'Trigger'],
|
package/src/index.ts
CHANGED
|
@@ -90,6 +90,8 @@ export {Text, type TextVariant, type TextColor} from './components/Text/Text'
|
|
|
90
90
|
export {Toggle, type ToggleSize} from './components/Toggle/Toggle'
|
|
91
91
|
export {ToggleGroup} from './components/ToggleGroup/ToggleGroup'
|
|
92
92
|
export {Tooltip} from './components/Tooltip/Tooltip'
|
|
93
|
+
export {Popover} from './components/Popover/Popover'
|
|
94
|
+
export type {PopoverHandle} from './components/Popover/Popover'
|
|
93
95
|
export {Switch} from './components/Switch/Switch'
|
|
94
96
|
|
|
95
97
|
// Layout primitives
|