@tcn/ui 0.12.1 → 0.12.3

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 (99) hide show
  1. package/dist/inputs/phone_number_input/phone_number_input_adapter.d.ts.map +1 -1
  2. package/dist/inputs/phone_number_input/phone_number_input_adapter.js +39 -34
  3. package/dist/inputs/phone_number_input/phone_number_input_adapter.js.map +1 -1
  4. package/dist/inputs/phone_number_input/sip_input.d.ts.map +1 -1
  5. package/dist/inputs/phone_number_input/sip_input.js +57 -52
  6. package/dist/inputs/phone_number_input/sip_input.js.map +1 -1
  7. package/dist/inputs/suggestions/suggestion_list.d.ts +8 -1
  8. package/dist/inputs/suggestions/suggestion_list.d.ts.map +1 -1
  9. package/dist/inputs/suggestions/suggestion_list.js +121 -111
  10. package/dist/inputs/suggestions/suggestion_list.js.map +1 -1
  11. package/dist/overlay/popper/base/dismissal_decorator.js +6 -6
  12. package/dist/overlay/popper/base/dismissal_decorator.js.map +1 -1
  13. package/dist/overlay/popper/context_popper.d.ts.map +1 -1
  14. package/dist/overlay/popper/context_popper.js +34 -26
  15. package/dist/overlay/popper/context_popper.js.map +1 -1
  16. package/dist/overlay/popper/element_popper.d.ts.map +1 -1
  17. package/dist/overlay/popper/element_popper.js +43 -25
  18. package/dist/overlay/popper/element_popper.js.map +1 -1
  19. package/dist/overlay/tethered/hooks/use_ref_dimensions.d.ts +3 -0
  20. package/dist/overlay/tethered/hooks/use_ref_dimensions.d.ts.map +1 -0
  21. package/dist/overlay/tethered/hooks/use_ref_dimensions.js +26 -0
  22. package/dist/overlay/tethered/hooks/use_ref_dimensions.js.map +1 -0
  23. package/dist/overlay/tethered/hooks/{useTether.d.ts → use_tether.d.ts} +7 -4
  24. package/dist/overlay/tethered/hooks/use_tether.d.ts.map +1 -0
  25. package/dist/overlay/tethered/hooks/{useTether.js → use_tether.js} +19 -15
  26. package/dist/overlay/tethered/hooks/use_tether.js.map +1 -0
  27. package/dist/overlay/tethered/hooks/use_tether_origin.d.ts +10 -0
  28. package/dist/overlay/tethered/hooks/use_tether_origin.d.ts.map +1 -0
  29. package/dist/overlay/tethered/hooks/use_tether_origin.js +22 -0
  30. package/dist/overlay/tethered/hooks/use_tether_origin.js.map +1 -0
  31. package/dist/overlay/tethered/hooks/{calculate_origin.d.ts → utils/calculate_origin.d.ts} +4 -10
  32. package/dist/overlay/tethered/hooks/utils/calculate_origin.d.ts.map +1 -0
  33. package/dist/overlay/tethered/hooks/utils/calculate_origin.js +41 -0
  34. package/dist/overlay/tethered/hooks/utils/calculate_origin.js.map +1 -0
  35. package/dist/overlay/tethered/hooks/{calculate_position.d.ts → utils/calculate_position.d.ts} +2 -2
  36. package/dist/overlay/tethered/hooks/utils/calculate_position.d.ts.map +1 -0
  37. package/dist/overlay/tethered/hooks/utils/calculate_position.js.map +1 -0
  38. package/dist/overlay/tethered/tethered.d.ts.map +1 -1
  39. package/dist/overlay/tethered/tethered.js +63 -62
  40. package/dist/overlay/tethered/tethered.js.map +1 -1
  41. package/dist/surfaces/pop_confirm/pop_confirm.js +7 -7
  42. package/dist/surfaces/pop_confirm/pop_confirm.js.map +1 -1
  43. package/dist/surfaces/tooltip/tooltip.d.ts.map +1 -1
  44. package/dist/surfaces/tooltip/tooltip.js +27 -28
  45. package/dist/surfaces/tooltip/tooltip.js.map +1 -1
  46. package/dist/themes/themes/ergo/ergo_theme.css +1 -1
  47. package/dist/themes/themes/ergo/ergo_theme.js +98 -8
  48. package/dist/themes/themes/ergo/ergo_theme.js.map +1 -1
  49. package/package.json +1 -1
  50. package/src/inputs/phone_number_input/phone_number_input.stories.tsx +7 -0
  51. package/src/inputs/phone_number_input/phone_number_input_adapter.tsx +5 -0
  52. package/src/inputs/phone_number_input/sip_input.tsx +5 -0
  53. package/src/inputs/select/select.stories.tsx +34 -11
  54. package/src/inputs/suggestions/suggestion_list.tsx +23 -6
  55. package/src/overlay/popper/base/dismissal_decorator.tsx +1 -1
  56. package/src/overlay/popper/context_popper.tsx +7 -3
  57. package/src/overlay/popper/element_popper.tsx +14 -4
  58. package/src/overlay/tethered/__stories__/shared/base_story_config.ts +1 -1
  59. package/src/overlay/tethered/hooks/use_ref_dimensions.ts +32 -0
  60. package/src/overlay/tethered/hooks/{useTether.ts → use_tether.ts} +7 -2
  61. package/src/overlay/tethered/hooks/use_tether_origin.ts +46 -0
  62. package/src/overlay/tethered/hooks/{calculate_origin.ts → utils/calculate_origin.ts} +12 -12
  63. package/src/overlay/tethered/hooks/{calculate_position.ts → utils/calculate_position.ts} +3 -3
  64. package/src/overlay/tethered/tethered.tsx +22 -26
  65. package/src/surfaces/pop_confirm/pop_confirm.stories.tsx +206 -6
  66. package/src/surfaces/pop_confirm/pop_confirm.tsx +1 -1
  67. package/src/surfaces/tooltip/__stories__/tooltip.stories.tsx +136 -0
  68. package/src/surfaces/tooltip/__stories__/tooltip_stories.module.css +14 -0
  69. package/src/surfaces/tooltip/tooltip.tsx +6 -2
  70. package/src/themes/themes/ergo/ergo_theme.css +98 -8
  71. package/dist/overlay/tethered/hooks/calculate_origin.d.ts.map +0 -1
  72. package/dist/overlay/tethered/hooks/calculate_origin.js +0 -41
  73. package/dist/overlay/tethered/hooks/calculate_origin.js.map +0 -1
  74. package/dist/overlay/tethered/hooks/calculate_position.d.ts.map +0 -1
  75. package/dist/overlay/tethered/hooks/calculate_position.js.map +0 -1
  76. package/dist/overlay/tethered/hooks/useCaretRefDimensions.d.ts +0 -9
  77. package/dist/overlay/tethered/hooks/useCaretRefDimensions.d.ts.map +0 -1
  78. package/dist/overlay/tethered/hooks/useCaretRefDimensions.js +0 -14
  79. package/dist/overlay/tethered/hooks/useCaretRefDimensions.js.map +0 -1
  80. package/dist/overlay/tethered/hooks/useTether.d.ts.map +0 -1
  81. package/dist/overlay/tethered/hooks/useTether.js.map +0 -1
  82. package/dist/overlay/tethered/hooks/useTetherContentRect.d.ts +0 -3
  83. package/dist/overlay/tethered/hooks/useTetherContentRect.d.ts.map +0 -1
  84. package/dist/overlay/tethered/hooks/useTetherContentRect.js +0 -36
  85. package/dist/overlay/tethered/hooks/useTetherContentRect.js.map +0 -1
  86. package/dist/overlay/tethered/hooks/useTetherOrigin.d.ts +0 -14
  87. package/dist/overlay/tethered/hooks/useTetherOrigin.d.ts.map +0 -1
  88. package/dist/overlay/tethered/hooks/useTetherOrigin.js +0 -24
  89. package/dist/overlay/tethered/hooks/useTetherOrigin.js.map +0 -1
  90. package/dist/surfaces/popconfirm/pop_confirm.d.ts +0 -5
  91. package/dist/surfaces/popconfirm/pop_confirm.d.ts.map +0 -1
  92. package/dist/surfaces/popconfirm/pop_confirm.js +0 -13
  93. package/dist/surfaces/popconfirm/pop_confirm.js.map +0 -1
  94. package/src/overlay/tethered/hooks/useCaretRefDimensions.ts +0 -22
  95. package/src/overlay/tethered/hooks/useTetherContentRect.ts +0 -49
  96. package/src/overlay/tethered/hooks/useTetherOrigin.ts +0 -49
  97. package/src/surfaces/popconfirm/pop_confirm.tsx +0 -18
  98. package/src/surfaces/tooltip/tooltip.stories.tsx +0 -54
  99. /package/dist/overlay/tethered/hooks/{calculate_position.js → utils/calculate_position.js} +0 -0
@@ -2,25 +2,35 @@ import { useRef, useState } from 'react';
2
2
  import { Button } from '../../actions/index.js';
3
3
  import { Footer, Header, Section, VBody } from '../../layouts/index.js';
4
4
  import { HStack } from '../../stacks/h_stack.js';
5
- import { PopConfirm as PopConfirmComponent } from './pop_confirm.js';
5
+ import { PopConfirm, type PopConfirmProps } from './pop_confirm.js';
6
6
  import { BodyText, Title } from '../../typography/index.js';
7
7
  import { VStack } from '../../stacks/v_stack.js';
8
8
  import { Spacer } from '../../stacks/spacer.js';
9
+ import { PopperDismissal } from '../../overlay/popper/base/dismissal_decorator.js';
10
+ import {
11
+ tetheredArgs,
12
+ tetheredArgTypes,
13
+ } from '../../overlay/tethered/__stories__/shared/base_story_config.js';
9
14
 
10
15
  export default {
11
16
  title: 'Surfaces/Pop Confirm',
12
- component: PopConfirmComponent,
17
+ component: PopConfirm,
13
18
  tags: ['autodocs'],
14
19
  parameters: {
15
20
  docs: {
16
21
  description: {
17
- component: 'A tooltip component that displays a tooltip when hovered.',
22
+ component:
23
+ 'A confirmation popover triggered by a button. Supports different dismissal behaviors: click away, mouse leave, and scroll away.',
18
24
  },
19
25
  },
20
26
  },
27
+ args: tetheredArgs,
28
+ argTypes: tetheredArgTypes,
21
29
  };
22
30
 
23
- export const DefaultPopConfirm = () => {
31
+ export const DefaultPopConfirm = (
32
+ args: Omit<PopConfirmProps, 'anchorElement' | 'open' | 'onDismissal'>
33
+ ) => {
24
34
  const anchorRef = useRef<HTMLButtonElement>(null);
25
35
  const [open, setOpen] = useState(false);
26
36
 
@@ -42,11 +52,14 @@ export const DefaultPopConfirm = () => {
42
52
  <Button ref={anchorRef} onClick={prompt}>
43
53
  Click to Confirm
44
54
  </Button>
45
- <PopConfirmComponent
55
+ <PopConfirm
46
56
  height={'200px'}
47
57
  open={open}
48
58
  onDismissal={cancel}
49
59
  anchorElement={anchorRef}
60
+ // PopperDismissal.CLICK_AWAY is the default dismissal behavior but shown here for demonstration purposes
61
+ dismissals={[PopperDismissal.CLICK_AWAY]}
62
+ {...args}
50
63
  >
51
64
  <Header>
52
65
  <Title>Confirmation Title</Title>
@@ -65,8 +78,195 @@ export const DefaultPopConfirm = () => {
65
78
  Confirm
66
79
  </Button>
67
80
  </Footer>
68
- </PopConfirmComponent>
81
+ </PopConfirm>
69
82
  </HStack>
70
83
  </VStack>
71
84
  );
72
85
  };
86
+
87
+ DefaultPopConfirm.parameters = {
88
+ docs: {
89
+ description: {
90
+ story:
91
+ 'Closes only when clicking outside the popover. Clicking inside (title, body, or buttons) keeps it open.',
92
+ },
93
+ },
94
+ };
95
+
96
+ export const ManualCloseOnly = () => {
97
+ const anchorRef = useRef<HTMLButtonElement>(null);
98
+ const [open, setOpen] = useState(false);
99
+
100
+ return (
101
+ <VStack hAlign="center" vAlign="center" height="100%" width="100%">
102
+ <HStack hAlign="center" vAlign="center">
103
+ <Button ref={anchorRef} onClick={() => setOpen(true)}>
104
+ Open
105
+ </Button>
106
+ <PopConfirm
107
+ height={'200px'}
108
+ open={open}
109
+ onDismissal={() => setOpen(false)}
110
+ anchorElement={anchorRef}
111
+ dismissals={[]}
112
+ >
113
+ <Header>
114
+ <Title>Must confirm or cancel</Title>
115
+ </Header>
116
+ <VBody>
117
+ <Section>
118
+ <BodyText>
119
+ No automatic dismissal. The popover stays open until you click Cancel or
120
+ Confirm. Clicking or scrolling outside does nothing.
121
+ </BodyText>
122
+ </Section>
123
+ </VBody>
124
+ <Footer>
125
+ <Spacer />
126
+ <Button hierarchy="secondary" onClick={() => setOpen(false)}>
127
+ Cancel
128
+ </Button>
129
+ <Button hierarchy="primary" onClick={() => setOpen(false)}>
130
+ Confirm
131
+ </Button>
132
+ </Footer>
133
+ </PopConfirm>
134
+ </HStack>
135
+ </VStack>
136
+ );
137
+ };
138
+
139
+ ManualCloseOnly.parameters = {
140
+ docs: {
141
+ description: {
142
+ story:
143
+ 'No dismissal behaviors. The popover only closes when the user clicks Cancel or Confirm—clicking outside, scrolling, or moving the pointer away has no effect.',
144
+ },
145
+ },
146
+ };
147
+
148
+ export const MouseLeaveOnly = () => {
149
+ const anchorRef = useRef<HTMLButtonElement>(null);
150
+ const [open, setOpen] = useState(false);
151
+
152
+ return (
153
+ <VStack hAlign="center" vAlign="center" height="100%" width="100%">
154
+ <HStack hAlign="center" vAlign="center">
155
+ <Button ref={anchorRef} onMouseEnter={() => setOpen(true)}>
156
+ Hover to confirm
157
+ </Button>
158
+ <PopConfirm
159
+ height={'200px'}
160
+ open={open}
161
+ onDismissal={() => setOpen(false)}
162
+ anchorElement={anchorRef}
163
+ dismissals={[PopperDismissal.MOUSE_LEAVE]}
164
+ >
165
+ <Header>
166
+ <Title>Confirm action</Title>
167
+ </Header>
168
+ <VBody>
169
+ <Section>
170
+ <BodyText>
171
+ Closes when the pointer leaves the popover and trigger area.
172
+ </BodyText>
173
+ </Section>
174
+ </VBody>
175
+ <Footer>
176
+ <Spacer />
177
+ <Button hierarchy="secondary" onClick={() => setOpen(false)}>
178
+ Cancel
179
+ </Button>
180
+ <Button hierarchy="primary" onClick={() => setOpen(false)}>
181
+ OK
182
+ </Button>
183
+ </Footer>
184
+ </PopConfirm>
185
+ </HStack>
186
+ </VStack>
187
+ );
188
+ };
189
+
190
+ MouseLeaveOnly.parameters = {
191
+ docs: {
192
+ description: {
193
+ story:
194
+ 'Closes when the mouse leaves the region (popover + trigger). No click-away or scroll-away. Suited to hover-triggered flows.',
195
+ },
196
+ },
197
+ };
198
+
199
+ export const ClickAwayAndScrollAway = () => {
200
+ const anchorRef = useRef<HTMLButtonElement>(null);
201
+ const [open, setOpen] = useState(false);
202
+
203
+ return (
204
+ <div
205
+ style={{
206
+ height: '320px',
207
+ overflow: 'auto',
208
+ padding: '16px',
209
+ boxSizing: 'border-box',
210
+ }}
211
+ >
212
+ <VStack gap="24px" padding="16px" style={{ minHeight: '600px' }}>
213
+ <Section>
214
+ <BodyText>
215
+ Scroll down to find the button and open the popover. Then scroll this
216
+ container—the popover will close when you scroll away.
217
+ </BodyText>
218
+ </Section>
219
+ <Spacer />
220
+ <HStack hAlign="center" vAlign="center">
221
+ <Button ref={anchorRef} onClick={() => setOpen(true)}>
222
+ Open
223
+ </Button>
224
+ <PopConfirm
225
+ height={'200px'}
226
+ open={open}
227
+ onDismissal={() => setOpen(false)}
228
+ anchorElement={anchorRef}
229
+ dismissals={[PopperDismissal.CLICK_AWAY, PopperDismissal.SCROLL_AWAY]}
230
+ >
231
+ <Header>
232
+ <Title>Scroll or click away</Title>
233
+ </Header>
234
+ <VBody>
235
+ <Section>
236
+ <BodyText>
237
+ Closes when you click outside or when you scroll outside the popover.
238
+ Scroll the container above or below to see it close.
239
+ </BodyText>
240
+ </Section>
241
+ </VBody>
242
+ <Footer>
243
+ <Spacer />
244
+ <Button hierarchy="secondary" onClick={() => setOpen(false)}>
245
+ Cancel
246
+ </Button>
247
+ <Button hierarchy="primary" onClick={() => setOpen(false)}>
248
+ Confirm
249
+ </Button>
250
+ </Footer>
251
+ </PopConfirm>
252
+ </HStack>
253
+ <Spacer />
254
+ <Section>
255
+ <BodyText>
256
+ More content below. After opening the popover, scroll up or down within this
257
+ panel—the popover dismisses because the scroll happened outside of it.
258
+ </BodyText>
259
+ </Section>
260
+ </VStack>
261
+ </div>
262
+ );
263
+ };
264
+
265
+ ClickAwayAndScrollAway.parameters = {
266
+ docs: {
267
+ description: {
268
+ story:
269
+ 'Closes on outside click or when scrolling outside the popover. This story uses a scrollable container—open the popover, then scroll the panel; the popover dismisses because the scroll happened outside it.',
270
+ },
271
+ },
272
+ };
@@ -14,7 +14,7 @@ export const PopConfirm = React.forwardRef<HTMLDivElement, PopConfirmProps>(
14
14
  {
15
15
  children,
16
16
  className,
17
- precision = 'low',
17
+ precision = 'high',
18
18
  dismissals = [PopperDismissal.CLICK_AWAY],
19
19
  ...props
20
20
  },
@@ -0,0 +1,136 @@
1
+ import { StyleBox } from '../../../stacks/story_components/style_box.js';
2
+ import { ZStack } from '../../../stacks/z_stack.js';
3
+ import { Tooltip as TooltipComponent, type TooltipProps } from '../tooltip.js';
4
+ import {
5
+ tetheredArgs,
6
+ tetheredArgTypes,
7
+ } from '../../../overlay/tethered/__stories__/shared/base_story_config.js';
8
+ import { BodyText, Title } from '../../../typography/index.js';
9
+ import { VStack } from '../../../stacks/v_stack.js';
10
+ import styles from './tooltip_stories.module.css';
11
+
12
+ export default {
13
+ title: 'Surfaces/Tooltip',
14
+ component: TooltipComponent,
15
+ tags: ['autodocs'],
16
+ parameters: {
17
+ docs: {
18
+ description: {
19
+ component: 'A tooltip component that displays a tooltip when hovered.',
20
+ },
21
+ },
22
+ },
23
+ argTypes: tetheredArgTypes,
24
+ args: tetheredArgs,
25
+ };
26
+
27
+ type TooltipStoryProps = TooltipProps & {
28
+ label: string;
29
+ };
30
+ export const DefaultTooltip = ({
31
+ label = 'Tooltip content',
32
+ precision = 'high',
33
+ ...args
34
+ }: TooltipStoryProps) => {
35
+ return (
36
+ <ZStack width="100%" minWidth="400px" minHeight="300px">
37
+ <TooltipComponent label={label} precision={precision} {...args}>
38
+ <StyleBox
39
+ backgroundColor="red"
40
+ padding="8px"
41
+ borderRadius={'8px'}
42
+ width="200px"
43
+ height="100px"
44
+ display="flex"
45
+ justifyContent="center"
46
+ alignItems="center"
47
+ >
48
+ Hover to open
49
+ </StyleBox>
50
+ </TooltipComponent>
51
+ </ZStack>
52
+ );
53
+ };
54
+
55
+ export const CustomTooltip = ({
56
+ label = 'Tooltip content',
57
+ precision = 'high',
58
+ ...args
59
+ }: TooltipStoryProps) => {
60
+ return (
61
+ <ZStack width="100%" minWidth="400px" minHeight="400px">
62
+ <TooltipComponent
63
+ className={styles.tooltip}
64
+ label={
65
+ <VStack
66
+ className={styles.label}
67
+ vAlign="center"
68
+ hAlign="center"
69
+ width="200px"
70
+ height="100px"
71
+ >
72
+ <Title>{label}</Title>
73
+ <BodyText>Custom Tooltip Content</BodyText>
74
+ </VStack>
75
+ }
76
+ precision={precision}
77
+ {...args}
78
+ >
79
+ <StyleBox
80
+ backgroundColor="red"
81
+ padding="8px"
82
+ borderRadius={'8px'}
83
+ width="200px"
84
+ height="100px"
85
+ display="flex"
86
+ justifyContent="center"
87
+ alignItems="center"
88
+ >
89
+ Hover to open
90
+ </StyleBox>
91
+ </TooltipComponent>
92
+ </ZStack>
93
+ );
94
+ };
95
+
96
+ export const CustomTooltipLabel = ({
97
+ label = 'Tooltip content',
98
+ precision = 'high',
99
+ ...args
100
+ }: TooltipStoryProps) => {
101
+ return (
102
+ <ZStack width="100%" minWidth="400px" minHeight="400px">
103
+ <TooltipComponent
104
+ label={
105
+ <VStack
106
+ className="tcn-tooltip-label"
107
+ vAlign="center"
108
+ hAlign="center"
109
+ width="200px"
110
+ height="100px"
111
+ >
112
+ <BodyText>✨ Can have custom children and styles</BodyText>
113
+ <BodyText>
114
+ ✨ But still inherits the themes tooltip label container styles
115
+ </BodyText>
116
+ </VStack>
117
+ }
118
+ precision={precision}
119
+ {...args}
120
+ >
121
+ <StyleBox
122
+ backgroundColor="red"
123
+ padding="8px"
124
+ borderRadius={'8px'}
125
+ width="200px"
126
+ height="100px"
127
+ display="flex"
128
+ justifyContent="center"
129
+ alignItems="center"
130
+ >
131
+ Hover to open
132
+ </StyleBox>
133
+ </TooltipComponent>
134
+ </ZStack>
135
+ );
136
+ };
@@ -0,0 +1,14 @@
1
+ .tooltip {
2
+ --custom-color: #e5735c;
3
+ color: #561a0b;
4
+
5
+ :global(.tcn-tethered-origin-indicator) {
6
+ border-top-color: var(--custom-color);
7
+ }
8
+
9
+ .label {
10
+ background-color: var(--custom-color);
11
+ border-radius: 8px;
12
+ gap: 8px;
13
+ }
14
+ }
@@ -22,7 +22,7 @@ export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(function T
22
22
  verticalOrigin = 'bottom',
23
23
  horizontalAnchor = 'center',
24
24
  horizontalOrigin = 'center',
25
- precision = 'low', // TODO: Fix caret styles and set to high
25
+ precision = 'high',
26
26
  label,
27
27
  ...props
28
28
  },
@@ -54,7 +54,11 @@ export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(function T
54
54
  className={clsx(className, styles.tooltip, 'tcn-surface', 'tcn-tooltip')}
55
55
  {...props}
56
56
  >
57
- {label}
57
+ {typeof label === 'string' ? (
58
+ <span className="tcn-tooltip-label">{label}</span>
59
+ ) : (
60
+ label
61
+ )}
58
62
  </PreviewPopper>
59
63
  </>
60
64
  );
@@ -89,6 +89,7 @@
89
89
  --shape-radius-small: 2px;
90
90
  --shape-radius-medium: 4px;
91
91
  --shape-radius-large: 8px;
92
+ --shape-triangle-medium: 12px;
92
93
 
93
94
  /* Palette */
94
95
  --primary-color-faint: #c0c0c0;
@@ -607,12 +608,88 @@
607
608
  border: inherit;
608
609
  }
609
610
 
611
+ .tcn-tethered {
612
+ /* Managing offset of the indicator in relation for the tethered element
613
+ pad defaults to 0, but should be set depending on the surface */
614
+
615
+ --tether-pad-x: 0px;
616
+ --tether-pad-y: 0px;
617
+ --indicator-pad-x: 0px;
618
+ --indicator-pad-y: 0px;
619
+ --tether-pad-size: 0px;
620
+ --tether-pad-pos: var(--tether-pad-size);
621
+ --tether-pad-neg: calc(-1 * var(--tether-pad-size));
622
+ left: calc(
623
+ var(--tether-pad-x, 0) -
624
+ var(--indicator-pad-x, 0) +
625
+ var(--tethered-left, 0)
626
+ );
627
+ top: calc(var(--tether-pad-y, 0) + var(--tethered-top, 0));
628
+
629
+ :where(.tcn-tethered-origin-indicator) {
630
+ left: calc(var(--indicator-pad-x, 0) + var(--tethered-origin-delta-x, 0));
631
+ top: calc(var(--indicator-pad-y, 0) + var(--tethered-origin-delta-y, 0));
632
+ }
633
+
634
+ &[data-h-anchor="start"] {
635
+ --tether-pad-x: var(--tether-pad-pos);
636
+ }
637
+
638
+ &[data-h-anchor="end"] {
639
+ --tether-pad-x: var(--tether-pad-neg);
640
+ }
641
+
642
+ &[data-h-origin="start"] {
643
+ --indicator-pad-x: var(--tether-pad-pos);
644
+ }
645
+
646
+ &[data-h-origin="end"] {
647
+ --indicator-pad-x: var(--tether-pad-neg);
648
+ }
649
+
650
+ &[data-v-origin="center"] {
651
+ --indicator-pad-x: 0px;
652
+ --tether-pad-x: 0px;
653
+ &[data-v-anchor="top"] {
654
+ --tether-pad-y: var(--tether-pad-pos);
655
+ }
656
+
657
+ &[data-v-anchor="bottom"] {
658
+ --tether-pad-y: var(--tether-pad-neg);
659
+ }
660
+ }
661
+
662
+ &[data-anchor-direction="bottom"] {
663
+ padding-bottom: var(--shape-triangle-medium);
664
+ }
665
+
666
+ &[data-anchor-direction="top"] {
667
+ padding-top: var(--shape-triangle-medium);
668
+ }
669
+
670
+ &[data-anchor-direction="start"] {
671
+ padding-left: var(--shape-triangle-medium);
672
+ }
673
+
674
+ &[data-anchor-direction="end"] {
675
+ padding-right: var(--shape-triangle-medium);
676
+ }
677
+ }
678
+
610
679
  .tcn-tooltip {
611
- background: rgba(57, 85, 120, 0.85);
612
- box-shadow: 0px 4px 7px 0px rgba(65, 65, 65, 0.66);
613
- color: rgba(255, 255, 255, 1);
614
- border-radius: var(--shape-radius-medium);
615
- padding: var(--padding-medium);
680
+ --tether-pad-size: 16px;
681
+ background: transparent;
682
+ --material: var(--ergo-secondary-dark);
683
+ --on-material: var(--ergo-white);
684
+ --action: var(--ergo-tertiary);
685
+ --on-action: var(--ergo-secondary-dark);
686
+ .tcn-tooltip-label {
687
+ box-shadow: 0px 4px 7px 0px rgba(65, 65, 65, 0.66);
688
+ color: var(--on-material);
689
+ background: var(--material);
690
+ border-radius: var(--shape-radius-medium);
691
+ padding: var(--padding-medium);
692
+ }
616
693
  }
617
694
 
618
695
  .tcn-list {
@@ -738,6 +815,17 @@
738
815
 
739
816
  .tcn-pop-confirm {
740
817
  --divide-header: 0;
818
+ --tether-pad-size: 16px;
819
+ :where(.tcn-tethered-origin-indicator) {
820
+ --material: var(--ergo-white);
821
+ }
822
+
823
+ /* Set the indicator to match the header color */
824
+ &[data-v-origin="top"] {
825
+ :where(.tcn-tethered-origin-indicator) {
826
+ --material: var(--ergo-secondary-dark);
827
+ }
828
+ }
741
829
 
742
830
  :where(.tcn-scaffold) {
743
831
  --pad-inline: var(--padding-medium);
@@ -860,14 +948,16 @@
860
948
  }
861
949
 
862
950
  .tcn-caret {
863
- --caret-size: 12px;
951
+ --caret-size: var(--shape-triangle-medium);
864
952
  --caret-triangle-height: calc(var(--caret-size) / 2);
865
953
  --caret-triangle-width: var(--caret-size);
866
954
  --caret-triangle-base: var(--caret-triangle-height) solid transparent;
867
955
  --caret-triangle-peak: var(--caret-triangle-width) solid var(--material);
868
956
 
869
- width: 0;
870
- height: 0;
957
+ width: var(--caret-size);
958
+ height: var(--caret-size);
959
+ min-width: var(--caret-size);
960
+ min-height: var(--caret-size);
871
961
  flex-grow: 0;
872
962
  display: inline-block;
873
963
 
@@ -1 +0,0 @@
1
- {"version":3,"file":"calculate_origin.d.ts","sourceRoot":"","sources":["../../../../src/overlay/tethered/hooks/calculate_origin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAEpE,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,cAAc,GACtB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CA+BtC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,gBAAgB,EAAE,QAAQ,EAC1B,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC3C,QAAQ,CAKV;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,gBAAgB,GACxB,cAAc,CAQhB"}
@@ -1,41 +0,0 @@
1
- function r(e, t, s) {
2
- let n = 0, i = 0;
3
- switch (s) {
4
- case "top":
5
- n = 0;
6
- break;
7
- case "center":
8
- n = e.dimensions.height / 2;
9
- break;
10
- case "bottom":
11
- n = e.dimensions.height;
12
- break;
13
- }
14
- switch (t) {
15
- case "start":
16
- i = 0;
17
- break;
18
- case "center":
19
- i = e.dimensions.width / 2;
20
- break;
21
- case "end":
22
- i = e.dimensions.width;
23
- break;
24
- }
25
- return { yOffset: n, xOffset: i };
26
- }
27
- function c(e, t) {
28
- return {
29
- x: e.x + t.xOffset,
30
- y: e.y + t.yOffset
31
- };
32
- }
33
- function f(e, t) {
34
- return e !== "center" ? e : t !== "center" ? t : "none";
35
- }
36
- export {
37
- f as getOriginDirection,
38
- r as getOriginOffset,
39
- c as getOriginPosition
40
- };
41
- //# sourceMappingURL=calculate_origin.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"calculate_origin.js","sources":["../../../../src/overlay/tethered/hooks/calculate_origin.ts"],"sourcesContent":["import type { Position, Rectangle } from '../../../utils/index.js';\nimport type { HorizontalTether, VerticalTether } from '../types.js';\n\nexport type CaretDirection = 'top' | 'bottom' | 'start' | 'end' | 'none';\n\n/**\n * Calculates the offset from the tethered element's top-left corner to the origin point\n * based on tether dimensions and origin alignment.\n */\nexport function getOriginOffset(\n tether: Rectangle,\n hOrigin: HorizontalTether,\n vOrigin: VerticalTether\n): { yOffset: number; xOffset: number } {\n let yOffset = 0;\n let xOffset = 0;\n\n // Calculate vertical offset\n switch (vOrigin) {\n case 'top':\n yOffset = 0;\n break;\n case 'center':\n yOffset = tether.dimensions.height / 2;\n break;\n case 'bottom':\n yOffset = tether.dimensions.height;\n break;\n }\n\n // Calculate horizontal offset\n switch (hOrigin) {\n case 'start':\n xOffset = 0;\n break;\n case 'center':\n xOffset = tether.dimensions.width / 2;\n break;\n case 'end':\n xOffset = tether.dimensions.width;\n break;\n }\n\n return { yOffset, xOffset };\n}\n\n/**\n * Adds offset to baseline position to get absolute origin position.\n */\nexport function getOriginPosition(\n baselinePosition: Position,\n offset: { yOffset: number; xOffset: number }\n): Position {\n return {\n x: baselinePosition.x + offset.xOffset,\n y: baselinePosition.y + offset.yOffset,\n };\n}\n\n/**\n * Determines caret direction based on origin values.\n */\nexport function getOriginDirection(\n vOrigin: VerticalTether,\n hOrigin: HorizontalTether\n): CaretDirection {\n if (vOrigin !== 'center') {\n return vOrigin;\n } else if (hOrigin !== 'center') {\n return hOrigin;\n } else {\n return 'none';\n }\n}\n"],"names":["getOriginOffset","tether","hOrigin","vOrigin","yOffset","xOffset","getOriginPosition","baselinePosition","offset","getOriginDirection"],"mappings":"AASO,SAASA,EACdC,GACAC,GACAC,GACsC;AACtC,MAAIC,IAAU,GACVC,IAAU;AAGd,UAAQF,GAAA;AAAA,IACN,KAAK;AACH,MAAAC,IAAU;AACV;AAAA,IACF,KAAK;AACH,MAAAA,IAAUH,EAAO,WAAW,SAAS;AACrC;AAAA,IACF,KAAK;AACH,MAAAG,IAAUH,EAAO,WAAW;AAC5B;AAAA,EAAA;AAIJ,UAAQC,GAAA;AAAA,IACN,KAAK;AACH,MAAAG,IAAU;AACV;AAAA,IACF,KAAK;AACH,MAAAA,IAAUJ,EAAO,WAAW,QAAQ;AACpC;AAAA,IACF,KAAK;AACH,MAAAI,IAAUJ,EAAO,WAAW;AAC5B;AAAA,EAAA;AAGJ,SAAO,EAAE,SAAAG,GAAS,SAAAC,EAAA;AACpB;AAKO,SAASC,EACdC,GACAC,GACU;AACV,SAAO;AAAA,IACL,GAAGD,EAAiB,IAAIC,EAAO;AAAA,IAC/B,GAAGD,EAAiB,IAAIC,EAAO;AAAA,EAAA;AAEnC;AAKO,SAASC,EACdN,GACAD,GACgB;AAChB,SAAIC,MAAY,WACPA,IACED,MAAY,WACdA,IAEA;AAEX;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"calculate_position.d.ts","sourceRoot":"","sources":["../../../../src/overlay/tethered/hooks/calculate_position.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,MAAM,WAAW,+BAA+B;IAC9C,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,KAAK,GAAG,KAAK,CAAC;IACzB,cAAc,EAAE,cAAc,CAAC;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,UAAU,CAAC;CACtB;AAED,eAAO,MAAM,yBAAyB,GAAI,gJAWvC,+BAA+B;;;CAiFjC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"calculate_position.js","sources":["../../../../src/overlay/tethered/hooks/calculate_position.ts"],"sourcesContent":["import type { HorizontalTether, VerticalTether } from '../types.js';\nimport type { Rectangle } from '../../../utils/index.js';\nimport type { Dimensions } from '../../../utils/index.js';\n\nexport interface CalculateTetheredPositionParams {\n anchor: Rectangle;\n tether: Rectangle;\n direction: 'ltr' | 'rtl';\n verticalAnchor: VerticalTether;\n verticalOrigin: VerticalTether;\n horizontalAnchor: HorizontalTether;\n horizontalOrigin: HorizontalTether;\n verticalOffset: number;\n horizontalOffset: number;\n viewport: Dimensions;\n}\n\nexport const calculateTetheredPosition = ({\n anchor,\n tether,\n direction,\n verticalAnchor,\n verticalOrigin,\n horizontalAnchor,\n horizontalOrigin,\n verticalOffset,\n horizontalOffset,\n viewport,\n}: CalculateTetheredPositionParams) => {\n const isRtl = direction === 'rtl';\n\n let top = anchor.position.y;\n let left = anchor.position.x;\n\n // Calculate vertical position\n switch (verticalAnchor) {\n case 'top':\n top += verticalOffset;\n break;\n case 'center':\n top += anchor.dimensions.height / 2;\n break;\n case 'bottom':\n top += anchor.dimensions.height - verticalOffset;\n break;\n }\n\n switch (verticalOrigin) {\n case 'top':\n break;\n case 'center':\n top -= tether.dimensions.height / 2;\n break;\n case 'bottom':\n top -= tether.dimensions.height;\n break;\n }\n\n // Calculate horizontal position with direction sensitivity\n if (horizontalAnchor === 'start') {\n left += isRtl ? anchor.dimensions.width + horizontalOffset : horizontalOffset;\n } else if (horizontalAnchor === 'center') {\n left += anchor.dimensions.width / 2;\n } else if (horizontalAnchor === 'end') {\n left += isRtl ? -horizontalOffset : anchor.dimensions.width + horizontalOffset;\n }\n\n // Adjust the origin based on RTL direction\n let adjustedHorizontalOrigin = horizontalOrigin;\n if (isRtl) {\n if (horizontalOrigin === 'start') {\n adjustedHorizontalOrigin = 'end';\n } else if (horizontalOrigin === 'end') {\n adjustedHorizontalOrigin = 'start';\n }\n }\n\n // Apply adjusted origin to the position calculation\n if (adjustedHorizontalOrigin === 'start') {\n // No adjustment needed\n } else if (adjustedHorizontalOrigin === 'center') {\n left -= tether.dimensions.width / 2;\n } else if (adjustedHorizontalOrigin === 'end') {\n left -= tether.dimensions.width;\n }\n\n // Ensure the popover stays within the viewport\n // Prevent overflow to the right\n if (left + tether.dimensions.width > viewport.width) {\n left = viewport.width - tether.dimensions.width;\n }\n\n // Prevent overflow to the left\n if (left < 0) {\n left = 0;\n }\n\n // Prevent overflow to the bottom\n // FIXME: doesn't account for padding.\n if (top + tether.dimensions.height > viewport.height) {\n top = viewport.height - tether.dimensions.height;\n }\n\n // Prevent overflow to the top\n if (top < 0) {\n top = 0;\n }\n\n return { top, left };\n};\n"],"names":["calculateTetheredPosition","anchor","tether","direction","verticalAnchor","verticalOrigin","horizontalAnchor","horizontalOrigin","verticalOffset","horizontalOffset","viewport","isRtl","top","left","adjustedHorizontalOrigin"],"mappings":"AAiBO,MAAMA,IAA4B,CAAC;AAAA,EACxC,QAAAC;AAAA,EACA,QAAAC;AAAA,EACA,WAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,UAAAC;AACF,MAAuC;AACrC,QAAMC,IAAQR,MAAc;AAE5B,MAAIS,IAAMX,EAAO,SAAS,GACtBY,IAAOZ,EAAO,SAAS;AAG3B,UAAQG,GAAA;AAAA,IACN,KAAK;AACH,MAAAQ,KAAOJ;AACP;AAAA,IACF,KAAK;AACH,MAAAI,KAAOX,EAAO,WAAW,SAAS;AAClC;AAAA,IACF,KAAK;AACH,MAAAW,KAAOX,EAAO,WAAW,SAASO;AAClC;AAAA,EAAA;AAGJ,UAAQH,GAAA;AAAA,IACN,KAAK;AACH;AAAA,IACF,KAAK;AACH,MAAAO,KAAOV,EAAO,WAAW,SAAS;AAClC;AAAA,IACF,KAAK;AACH,MAAAU,KAAOV,EAAO,WAAW;AACzB;AAAA,EAAA;AAIJ,EAAII,MAAqB,UACvBO,KAAQF,IAAQV,EAAO,WAAW,QAAQQ,IAAmBA,IACpDH,MAAqB,WAC9BO,KAAQZ,EAAO,WAAW,QAAQ,IACzBK,MAAqB,UAC9BO,KAAQF,IAAQ,CAACF,IAAmBR,EAAO,WAAW,QAAQQ;AAIhE,MAAIK,IAA2BP;AAC/B,SAAII,MACEJ,MAAqB,UACvBO,IAA2B,QAClBP,MAAqB,UAC9BO,IAA2B,WAK3BA,MAA6B,YAEtBA,MAA6B,WACtCD,KAAQX,EAAO,WAAW,QAAQ,IACzBY,MAA6B,UACtCD,KAAQX,EAAO,WAAW,SAKxBW,IAAOX,EAAO,WAAW,QAAQQ,EAAS,UAC5CG,IAAOH,EAAS,QAAQR,EAAO,WAAW,QAIxCW,IAAO,MACTA,IAAO,IAKLD,IAAMV,EAAO,WAAW,SAASQ,EAAS,WAC5CE,IAAMF,EAAS,SAASR,EAAO,WAAW,SAIxCU,IAAM,MACRA,IAAM,IAGD,EAAE,KAAAA,GAAK,MAAAC,EAAA;AAChB;"}
@@ -1,9 +0,0 @@
1
- import { CaretDirection } from './calculate_origin.js';
2
- export declare function useCaretRefDimensions(precision: 'high' | 'low', originDirection: CaretDirection): {
3
- caretElementRef: (element: HTMLElement | null) => void;
4
- caretSize: {
5
- width: number;
6
- height: number;
7
- };
8
- };
9
- //# sourceMappingURL=useCaretRefDimensions.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useCaretRefDimensions.d.ts","sourceRoot":"","sources":["../../../../src/overlay/tethered/hooks/useCaretRefDimensions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,GAAG,KAAK,EACzB,eAAe,EAAE,cAAc,GAC9B;IACD,eAAe,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;IACvD,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C,CAYA"}
@@ -1,14 +0,0 @@
1
- import { useState as i, useLayoutEffect as c } from "react";
2
- function u(t, n) {
3
- const [e, r] = i(null), [s, a] = i({ width: 0, height: 0 });
4
- return c(() => {
5
- if (t === "high" && n !== "none" && e) {
6
- const h = e.getBoundingClientRect();
7
- a({ width: h.width, height: h.height });
8
- }
9
- }, [t, n, e]), { caretElementRef: r, caretSize: s };
10
- }
11
- export {
12
- u as useCaretRefDimensions
13
- };
14
- //# sourceMappingURL=useCaretRefDimensions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useCaretRefDimensions.js","sources":["../../../../src/overlay/tethered/hooks/useCaretRefDimensions.ts"],"sourcesContent":["import { useLayoutEffect, useState } from 'react';\nimport type { CaretDirection } from './calculate_origin.js';\n\nexport function useCaretRefDimensions(\n precision: 'high' | 'low',\n originDirection: CaretDirection\n): {\n caretElementRef: (element: HTMLElement | null) => void;\n caretSize: { width: number; height: number };\n} {\n const [caretElement, setCaretElement] = useState<HTMLElement | null>(null);\n const [caretSize, setCaretSize] = useState({ width: 0, height: 0 });\n\n useLayoutEffect(() => {\n if (precision === 'high' && originDirection !== 'none' && caretElement) {\n const rect = caretElement.getBoundingClientRect();\n setCaretSize({ width: rect.width, height: rect.height });\n }\n }, [precision, originDirection, caretElement]);\n\n return { caretElementRef: setCaretElement, caretSize };\n}\n"],"names":["useCaretRefDimensions","precision","originDirection","caretElement","setCaretElement","useState","caretSize","setCaretSize","useLayoutEffect","rect"],"mappings":";AAGO,SAASA,EACdC,GACAC,GAIA;AACA,QAAM,CAACC,GAAcC,CAAe,IAAIC,EAA6B,IAAI,GACnE,CAACC,GAAWC,CAAY,IAAIF,EAAS,EAAE,OAAO,GAAG,QAAQ,GAAG;AAElE,SAAAG,EAAgB,MAAM;AACpB,QAAIP,MAAc,UAAUC,MAAoB,UAAUC,GAAc;AACtE,YAAMM,IAAON,EAAa,sBAAA;AAC1B,MAAAI,EAAa,EAAE,OAAOE,EAAK,OAAO,QAAQA,EAAK,QAAQ;AAAA,IACzD;AAAA,EACF,GAAG,CAACR,GAAWC,GAAiBC,CAAY,CAAC,GAEtC,EAAE,iBAAiBC,GAAiB,WAAAE,EAAA;AAC7C;"}