@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.
Files changed (34) hide show
  1. package/dist/components/DetailPanel/DetailPanel.meta.d.ts.map +1 -1
  2. package/dist/components/Dialog/Dialog.meta.d.ts.map +1 -1
  3. package/dist/components/Drawer/Drawer.meta.d.ts.map +1 -1
  4. package/dist/components/Menu/Menu.meta.d.ts.map +1 -1
  5. package/dist/components/Popover/Popover.d.ts +41 -0
  6. package/dist/components/Popover/Popover.d.ts.map +1 -0
  7. package/dist/components/Popover/Popover.meta.d.ts +3 -0
  8. package/dist/components/Popover/Popover.meta.d.ts.map +1 -0
  9. package/dist/components/Popover/Popover.stories.d.ts +11 -0
  10. package/dist/components/Popover/Popover.stories.d.ts.map +1 -0
  11. package/dist/components/Popover/outside.d.ts +2 -0
  12. package/dist/components/Popover/outside.d.ts.map +1 -0
  13. package/dist/components/Popover/position.d.ts +27 -0
  14. package/dist/components/Popover/position.d.ts.map +1 -0
  15. package/dist/components/Popover/styles.css.d.ts +61 -0
  16. package/dist/components/Popover/styles.css.d.ts.map +1 -0
  17. package/dist/index.css +1 -1
  18. package/dist/index.d.ts +2 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1645 -1381
  21. package/dist/index.js.map +1 -1
  22. package/package.json +2 -2
  23. package/src/components/DetailPanel/DetailPanel.meta.ts +6 -0
  24. package/src/components/Dialog/Dialog.meta.ts +6 -0
  25. package/src/components/Drawer/Drawer.meta.ts +6 -0
  26. package/src/components/Menu/Menu.meta.ts +5 -1
  27. package/src/components/Popover/Popover.meta.ts +69 -0
  28. package/src/components/Popover/Popover.stories.tsx +250 -0
  29. package/src/components/Popover/Popover.tsx +293 -0
  30. package/src/components/Popover/outside.ts +9 -0
  31. package/src/components/Popover/position.ts +48 -0
  32. package/src/components/Popover/styles.css.ts +75 -0
  33. package/src/components/Tooltip/Tooltip.meta.ts +1 -1
  34. 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