@ims360/svelte-ivory 0.3.3 → 0.3.4
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/inputs/PasswordCreateInput.svelte +2 -0
- package/dist/components/layout/popover/Popover.svelte +125 -55
- package/dist/components/layout/popover/Popover.svelte.d.ts +2 -10
- package/dist/components/layout/popover/Popover.svelte.d.ts.map +1 -1
- package/package.json +1 -2
- package/src/lib/components/inputs/PasswordCreateInput.svelte +2 -0
- package/src/lib/components/layout/popover/Popover.svelte +125 -55
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
style="min-width: {target?.getBoundingClientRect().width}px;"
|
|
34
34
|
class="py-3"
|
|
35
35
|
placement="top"
|
|
36
|
+
autoplacement
|
|
37
|
+
popover="manual"
|
|
36
38
|
>
|
|
37
39
|
<div class="bg-surface-50-950 flex w-full flex-col gap-2 rounded p-4 shadow-lg">
|
|
38
40
|
{#each requirements as requirement (requirement.re)}
|
|
@@ -1,39 +1,36 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
|
-
import { browser } from '$app/environment';
|
|
3
2
|
import { theme } from '../../../theme.svelte';
|
|
4
3
|
import type { IvoryComponent } from '../../../types';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
autoPlacement,
|
|
8
|
-
autoUpdate,
|
|
9
|
-
computePosition,
|
|
10
|
-
flip,
|
|
11
|
-
shift,
|
|
12
|
-
type ComputePositionConfig
|
|
13
|
-
} from '@floating-ui/dom';
|
|
4
|
+
import { pseudoRandomId } from '../../../utils/functions';
|
|
14
5
|
import clsx from 'clsx';
|
|
15
6
|
import { twMerge } from 'tailwind-merge';
|
|
16
7
|
|
|
17
8
|
/** Possible placements for the popover */
|
|
18
|
-
export type PopoverPlacement =
|
|
9
|
+
export type PopoverPlacement =
|
|
10
|
+
| 'top'
|
|
11
|
+
| 'top-start'
|
|
12
|
+
| 'top-end'
|
|
13
|
+
| 'right'
|
|
14
|
+
| 'right-start'
|
|
15
|
+
| 'right-end'
|
|
16
|
+
| 'bottom'
|
|
17
|
+
| 'bottom-start'
|
|
18
|
+
| 'bottom-end'
|
|
19
|
+
| 'left'
|
|
20
|
+
| 'left-start'
|
|
21
|
+
| 'left-end';
|
|
19
22
|
|
|
20
23
|
export interface PopoverProps extends IvoryComponent<HTMLDivElement> {
|
|
21
24
|
/** The element the popover will be positioned relative to */
|
|
22
|
-
target:
|
|
25
|
+
target: HTMLElement | undefined;
|
|
23
26
|
/**
|
|
24
27
|
* Where the popover should be positioned relative to the target.
|
|
25
28
|
*
|
|
26
29
|
* default: `bottom-start`
|
|
27
30
|
*/
|
|
28
31
|
placement?: PopoverPlacement;
|
|
29
|
-
/**
|
|
30
|
-
* Callback that is called when the user clicks outside the popover or the target element.
|
|
31
|
-
*/
|
|
32
|
-
onClickOutside?: (e: MouseEvent) => void;
|
|
33
32
|
/**
|
|
34
33
|
* Whether to place the popover automatically
|
|
35
|
-
*
|
|
36
|
-
* [Further reading](https://floating-ui.com/docs/autoPlacement)
|
|
37
34
|
*/
|
|
38
35
|
autoplacement?: boolean;
|
|
39
36
|
}
|
|
@@ -45,66 +42,139 @@
|
|
|
45
42
|
style: externalStyle,
|
|
46
43
|
target,
|
|
47
44
|
placement = 'bottom-start',
|
|
48
|
-
onClickOutside = close,
|
|
49
45
|
children,
|
|
50
46
|
autoplacement,
|
|
47
|
+
popover = 'auto',
|
|
51
48
|
...rest
|
|
52
49
|
}: PopoverProps = $props();
|
|
53
50
|
|
|
54
|
-
let
|
|
55
|
-
|
|
51
|
+
let popoverEl: HTMLDivElement | undefined = $state();
|
|
52
|
+
const anchorName = `--${pseudoRandomId('anchor-')}`;
|
|
53
|
+
|
|
54
|
+
const getStyles = (
|
|
55
|
+
placement: PopoverPlacement,
|
|
56
|
+
anchorName: string,
|
|
57
|
+
autoplacement?: boolean
|
|
58
|
+
) => {
|
|
59
|
+
let styles = `position-anchor: ${anchorName}; margin: 0; inset: auto;`;
|
|
60
|
+
if (autoplacement) {
|
|
61
|
+
styles += ` position-try: flip-block, flip-inline;`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
switch (placement) {
|
|
65
|
+
case 'top':
|
|
66
|
+
return (
|
|
67
|
+
styles +
|
|
68
|
+
` bottom: anchor(${anchorName} top); left: anchor(${anchorName} center); translate: -50% 0;`
|
|
69
|
+
);
|
|
70
|
+
case 'top-start':
|
|
71
|
+
return (
|
|
72
|
+
styles +
|
|
73
|
+
` bottom: anchor(${anchorName} top); left: anchor(${anchorName} start);`
|
|
74
|
+
);
|
|
75
|
+
case 'top-end':
|
|
76
|
+
return (
|
|
77
|
+
styles + ` bottom: anchor(${anchorName} top); right: anchor(${anchorName} end);`
|
|
78
|
+
);
|
|
56
79
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
80
|
+
case 'bottom':
|
|
81
|
+
return (
|
|
82
|
+
styles +
|
|
83
|
+
` top: anchor(${anchorName} bottom); left: anchor(${anchorName} center); translate: -50% 0;`
|
|
84
|
+
);
|
|
85
|
+
case 'bottom-start':
|
|
86
|
+
return (
|
|
87
|
+
styles +
|
|
88
|
+
` top: anchor(${anchorName} bottom); left: anchor(${anchorName} start);`
|
|
89
|
+
);
|
|
90
|
+
case 'bottom-end':
|
|
91
|
+
return (
|
|
92
|
+
styles + ` top: anchor(${anchorName} bottom); right: anchor(${anchorName} end);`
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
case 'left':
|
|
96
|
+
return (
|
|
97
|
+
styles +
|
|
98
|
+
` right: anchor(${anchorName} left); top: anchor(${anchorName} center); translate: 0 -50%;`
|
|
99
|
+
);
|
|
100
|
+
case 'left-start':
|
|
101
|
+
return (
|
|
102
|
+
styles + ` right: anchor(${anchorName} left); top: anchor(${anchorName} top);`
|
|
103
|
+
);
|
|
104
|
+
case 'left-end':
|
|
105
|
+
return (
|
|
106
|
+
styles +
|
|
107
|
+
` right: anchor(${anchorName} left); bottom: anchor(${anchorName} bottom);`
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
case 'right':
|
|
111
|
+
return (
|
|
112
|
+
styles +
|
|
113
|
+
` left: anchor(${anchorName} right); top: anchor(${anchorName} center); translate: 0 -50%;`
|
|
114
|
+
);
|
|
115
|
+
case 'right-start':
|
|
116
|
+
return (
|
|
117
|
+
styles + ` left: anchor(${anchorName} right); top: anchor(${anchorName} top);`
|
|
118
|
+
);
|
|
119
|
+
case 'right-end':
|
|
120
|
+
return (
|
|
121
|
+
styles +
|
|
122
|
+
` left: anchor(${anchorName} right); bottom: anchor(${anchorName} bottom);`
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
default:
|
|
126
|
+
return (
|
|
127
|
+
styles +
|
|
128
|
+
` top: anchor(${anchorName} bottom); left: anchor(${anchorName} start);`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
64
131
|
};
|
|
65
132
|
|
|
66
133
|
let currentlyOpen = $state(false);
|
|
134
|
+
let style = $derived(getStyles(placement, anchorName, autoplacement));
|
|
135
|
+
|
|
136
|
+
$effect(() => {
|
|
137
|
+
if (target) {
|
|
138
|
+
target.style.setProperty('anchor-name', anchorName);
|
|
139
|
+
return () => {
|
|
140
|
+
target.style.removeProperty('anchor-name');
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
$effect(() => {
|
|
146
|
+
if (!popoverEl) return;
|
|
147
|
+
|
|
148
|
+
const handleToggle = (e: ToggleEvent) => {
|
|
149
|
+
const newState = e.newState === 'open';
|
|
150
|
+
currentlyOpen = newState;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
popoverEl.addEventListener('toggle', handleToggle);
|
|
154
|
+
return () => popoverEl?.removeEventListener('toggle', handleToggle);
|
|
155
|
+
});
|
|
67
156
|
|
|
68
|
-
let cleanup: () => void = () => {};
|
|
69
157
|
export function close() {
|
|
70
|
-
|
|
71
|
-
cleanup();
|
|
158
|
+
popoverEl?.hidePopover();
|
|
72
159
|
}
|
|
73
160
|
|
|
74
161
|
export function open() {
|
|
75
|
-
|
|
76
|
-
if (!target || !popover) return;
|
|
77
|
-
cleanup = autoUpdate(target, popover, () => postion(true));
|
|
162
|
+
if (popoverEl) popoverEl.showPopover();
|
|
78
163
|
}
|
|
79
164
|
|
|
80
165
|
export function toggle() {
|
|
81
|
-
currentlyOpen
|
|
166
|
+
if (currentlyOpen) close();
|
|
167
|
+
else open();
|
|
82
168
|
}
|
|
83
169
|
|
|
170
|
+
// Now this is reactive!
|
|
84
171
|
export function isOpen() {
|
|
85
172
|
return currentlyOpen;
|
|
86
173
|
}
|
|
87
|
-
|
|
88
|
-
// TODO: this is kinda hacky
|
|
89
|
-
$effect(() => {
|
|
90
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
91
|
-
[popover, target];
|
|
92
|
-
postion(currentlyOpen);
|
|
93
|
-
});
|
|
94
174
|
</script>
|
|
95
175
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
A popover, positions itself relative to a target element.
|
|
99
|
-
-->
|
|
100
|
-
{#if currentlyOpen}
|
|
101
|
-
<div
|
|
102
|
-
class={twMerge(clsx('absolute', theme.current.popover?.class, clazz))}
|
|
103
|
-
style={style + ' ' + externalStyle}
|
|
104
|
-
bind:this={popover}
|
|
105
|
-
{@attach clickOutside({ callback: onClickOutside, target })}
|
|
106
|
-
{...rest}
|
|
107
|
-
>
|
|
176
|
+
<div bind:this={popoverEl} {style} {popover} class="bg-transparent">
|
|
177
|
+
<div class={twMerge(clsx(theme.current.popover?.class, clazz))} style={externalStyle} {...rest}>
|
|
108
178
|
{@render children?.()}
|
|
109
179
|
</div>
|
|
110
|
-
|
|
180
|
+
</div>
|
|
@@ -1,28 +1,20 @@
|
|
|
1
1
|
import type { IvoryComponent } from '../../../types';
|
|
2
|
-
import { type ComputePositionConfig } from '@floating-ui/dom';
|
|
3
2
|
/** Possible placements for the popover */
|
|
4
|
-
export type PopoverPlacement =
|
|
3
|
+
export type PopoverPlacement = 'top' | 'top-start' | 'top-end' | 'right' | 'right-start' | 'right-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end';
|
|
5
4
|
export interface PopoverProps extends IvoryComponent<HTMLDivElement> {
|
|
6
5
|
/** The element the popover will be positioned relative to */
|
|
7
|
-
target:
|
|
6
|
+
target: HTMLElement | undefined;
|
|
8
7
|
/**
|
|
9
8
|
* Where the popover should be positioned relative to the target.
|
|
10
9
|
*
|
|
11
10
|
* default: `bottom-start`
|
|
12
11
|
*/
|
|
13
12
|
placement?: PopoverPlacement;
|
|
14
|
-
/**
|
|
15
|
-
* Callback that is called when the user clicks outside the popover or the target element.
|
|
16
|
-
*/
|
|
17
|
-
onClickOutside?: (e: MouseEvent) => void;
|
|
18
13
|
/**
|
|
19
14
|
* Whether to place the popover automatically
|
|
20
|
-
*
|
|
21
|
-
* [Further reading](https://floating-ui.com/docs/autoPlacement)
|
|
22
15
|
*/
|
|
23
16
|
autoplacement?: boolean;
|
|
24
17
|
}
|
|
25
|
-
/** A popover, positions itself relative to a target element. */
|
|
26
18
|
declare const Popover: import("svelte").Component<PopoverProps, {
|
|
27
19
|
close: () => void;
|
|
28
20
|
open: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popover.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/layout/popover/Popover.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Popover.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/layout/popover/Popover.svelte.ts"],"names":[],"mappings":"AAII,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKjD,0CAA0C;AAC1C,MAAM,MAAM,gBAAgB,GACtB,KAAK,GACL,WAAW,GACX,SAAS,GACT,OAAO,GACP,aAAa,GACb,WAAW,GACX,QAAQ,GACR,cAAc,GACd,YAAY,GACZ,MAAM,GACN,YAAY,GACZ,UAAU,CAAC;AAEjB,MAAM,WAAW,YAAa,SAAQ,cAAc,CAAC,cAAc,CAAC;IAChE,6DAA6D;IAC7D,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IAChC;;;;OAIG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CAC3B;AAqJL,QAAA,MAAM,OAAO;;;;;MAAwC,CAAC;AACtD,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAC1C,eAAe,OAAO,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ims360/svelte-ivory",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"svelte"
|
|
6
6
|
],
|
|
@@ -71,7 +71,6 @@
|
|
|
71
71
|
"test:unit": "vitest"
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {
|
|
74
|
-
"@floating-ui/dom": "^1.7.4",
|
|
75
74
|
"@lucide/svelte": "^0.553.0",
|
|
76
75
|
"@oddbird/css-anchor-positioning": "^0.8.0",
|
|
77
76
|
"@tailwindcss/forms": "^0.5.10",
|
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
style="min-width: {target?.getBoundingClientRect().width}px;"
|
|
34
34
|
class="py-3"
|
|
35
35
|
placement="top"
|
|
36
|
+
autoplacement
|
|
37
|
+
popover="manual"
|
|
36
38
|
>
|
|
37
39
|
<div class="bg-surface-50-950 flex w-full flex-col gap-2 rounded p-4 shadow-lg">
|
|
38
40
|
{#each requirements as requirement (requirement.re)}
|
|
@@ -1,39 +1,36 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
|
-
import { browser } from '$app/environment';
|
|
3
2
|
import { theme } from '$lib/theme.svelte';
|
|
4
3
|
import type { IvoryComponent } from '$lib/types';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
autoPlacement,
|
|
8
|
-
autoUpdate,
|
|
9
|
-
computePosition,
|
|
10
|
-
flip,
|
|
11
|
-
shift,
|
|
12
|
-
type ComputePositionConfig
|
|
13
|
-
} from '@floating-ui/dom';
|
|
4
|
+
import { pseudoRandomId } from '$lib/utils/functions';
|
|
14
5
|
import clsx from 'clsx';
|
|
15
6
|
import { twMerge } from 'tailwind-merge';
|
|
16
7
|
|
|
17
8
|
/** Possible placements for the popover */
|
|
18
|
-
export type PopoverPlacement =
|
|
9
|
+
export type PopoverPlacement =
|
|
10
|
+
| 'top'
|
|
11
|
+
| 'top-start'
|
|
12
|
+
| 'top-end'
|
|
13
|
+
| 'right'
|
|
14
|
+
| 'right-start'
|
|
15
|
+
| 'right-end'
|
|
16
|
+
| 'bottom'
|
|
17
|
+
| 'bottom-start'
|
|
18
|
+
| 'bottom-end'
|
|
19
|
+
| 'left'
|
|
20
|
+
| 'left-start'
|
|
21
|
+
| 'left-end';
|
|
19
22
|
|
|
20
23
|
export interface PopoverProps extends IvoryComponent<HTMLDivElement> {
|
|
21
24
|
/** The element the popover will be positioned relative to */
|
|
22
|
-
target:
|
|
25
|
+
target: HTMLElement | undefined;
|
|
23
26
|
/**
|
|
24
27
|
* Where the popover should be positioned relative to the target.
|
|
25
28
|
*
|
|
26
29
|
* default: `bottom-start`
|
|
27
30
|
*/
|
|
28
31
|
placement?: PopoverPlacement;
|
|
29
|
-
/**
|
|
30
|
-
* Callback that is called when the user clicks outside the popover or the target element.
|
|
31
|
-
*/
|
|
32
|
-
onClickOutside?: (e: MouseEvent) => void;
|
|
33
32
|
/**
|
|
34
33
|
* Whether to place the popover automatically
|
|
35
|
-
*
|
|
36
|
-
* [Further reading](https://floating-ui.com/docs/autoPlacement)
|
|
37
34
|
*/
|
|
38
35
|
autoplacement?: boolean;
|
|
39
36
|
}
|
|
@@ -45,66 +42,139 @@
|
|
|
45
42
|
style: externalStyle,
|
|
46
43
|
target,
|
|
47
44
|
placement = 'bottom-start',
|
|
48
|
-
onClickOutside = close,
|
|
49
45
|
children,
|
|
50
46
|
autoplacement,
|
|
47
|
+
popover = 'auto',
|
|
51
48
|
...rest
|
|
52
49
|
}: PopoverProps = $props();
|
|
53
50
|
|
|
54
|
-
let
|
|
55
|
-
|
|
51
|
+
let popoverEl: HTMLDivElement | undefined = $state();
|
|
52
|
+
const anchorName = `--${pseudoRandomId('anchor-')}`;
|
|
53
|
+
|
|
54
|
+
const getStyles = (
|
|
55
|
+
placement: PopoverPlacement,
|
|
56
|
+
anchorName: string,
|
|
57
|
+
autoplacement?: boolean
|
|
58
|
+
) => {
|
|
59
|
+
let styles = `position-anchor: ${anchorName}; margin: 0; inset: auto;`;
|
|
60
|
+
if (autoplacement) {
|
|
61
|
+
styles += ` position-try: flip-block, flip-inline;`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
switch (placement) {
|
|
65
|
+
case 'top':
|
|
66
|
+
return (
|
|
67
|
+
styles +
|
|
68
|
+
` bottom: anchor(${anchorName} top); left: anchor(${anchorName} center); translate: -50% 0;`
|
|
69
|
+
);
|
|
70
|
+
case 'top-start':
|
|
71
|
+
return (
|
|
72
|
+
styles +
|
|
73
|
+
` bottom: anchor(${anchorName} top); left: anchor(${anchorName} start);`
|
|
74
|
+
);
|
|
75
|
+
case 'top-end':
|
|
76
|
+
return (
|
|
77
|
+
styles + ` bottom: anchor(${anchorName} top); right: anchor(${anchorName} end);`
|
|
78
|
+
);
|
|
56
79
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
80
|
+
case 'bottom':
|
|
81
|
+
return (
|
|
82
|
+
styles +
|
|
83
|
+
` top: anchor(${anchorName} bottom); left: anchor(${anchorName} center); translate: -50% 0;`
|
|
84
|
+
);
|
|
85
|
+
case 'bottom-start':
|
|
86
|
+
return (
|
|
87
|
+
styles +
|
|
88
|
+
` top: anchor(${anchorName} bottom); left: anchor(${anchorName} start);`
|
|
89
|
+
);
|
|
90
|
+
case 'bottom-end':
|
|
91
|
+
return (
|
|
92
|
+
styles + ` top: anchor(${anchorName} bottom); right: anchor(${anchorName} end);`
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
case 'left':
|
|
96
|
+
return (
|
|
97
|
+
styles +
|
|
98
|
+
` right: anchor(${anchorName} left); top: anchor(${anchorName} center); translate: 0 -50%;`
|
|
99
|
+
);
|
|
100
|
+
case 'left-start':
|
|
101
|
+
return (
|
|
102
|
+
styles + ` right: anchor(${anchorName} left); top: anchor(${anchorName} top);`
|
|
103
|
+
);
|
|
104
|
+
case 'left-end':
|
|
105
|
+
return (
|
|
106
|
+
styles +
|
|
107
|
+
` right: anchor(${anchorName} left); bottom: anchor(${anchorName} bottom);`
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
case 'right':
|
|
111
|
+
return (
|
|
112
|
+
styles +
|
|
113
|
+
` left: anchor(${anchorName} right); top: anchor(${anchorName} center); translate: 0 -50%;`
|
|
114
|
+
);
|
|
115
|
+
case 'right-start':
|
|
116
|
+
return (
|
|
117
|
+
styles + ` left: anchor(${anchorName} right); top: anchor(${anchorName} top);`
|
|
118
|
+
);
|
|
119
|
+
case 'right-end':
|
|
120
|
+
return (
|
|
121
|
+
styles +
|
|
122
|
+
` left: anchor(${anchorName} right); bottom: anchor(${anchorName} bottom);`
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
default:
|
|
126
|
+
return (
|
|
127
|
+
styles +
|
|
128
|
+
` top: anchor(${anchorName} bottom); left: anchor(${anchorName} start);`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
64
131
|
};
|
|
65
132
|
|
|
66
133
|
let currentlyOpen = $state(false);
|
|
134
|
+
let style = $derived(getStyles(placement, anchorName, autoplacement));
|
|
135
|
+
|
|
136
|
+
$effect(() => {
|
|
137
|
+
if (target) {
|
|
138
|
+
target.style.setProperty('anchor-name', anchorName);
|
|
139
|
+
return () => {
|
|
140
|
+
target.style.removeProperty('anchor-name');
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
$effect(() => {
|
|
146
|
+
if (!popoverEl) return;
|
|
147
|
+
|
|
148
|
+
const handleToggle = (e: ToggleEvent) => {
|
|
149
|
+
const newState = e.newState === 'open';
|
|
150
|
+
currentlyOpen = newState;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
popoverEl.addEventListener('toggle', handleToggle);
|
|
154
|
+
return () => popoverEl?.removeEventListener('toggle', handleToggle);
|
|
155
|
+
});
|
|
67
156
|
|
|
68
|
-
let cleanup: () => void = () => {};
|
|
69
157
|
export function close() {
|
|
70
|
-
|
|
71
|
-
cleanup();
|
|
158
|
+
popoverEl?.hidePopover();
|
|
72
159
|
}
|
|
73
160
|
|
|
74
161
|
export function open() {
|
|
75
|
-
|
|
76
|
-
if (!target || !popover) return;
|
|
77
|
-
cleanup = autoUpdate(target, popover, () => postion(true));
|
|
162
|
+
if (popoverEl) popoverEl.showPopover();
|
|
78
163
|
}
|
|
79
164
|
|
|
80
165
|
export function toggle() {
|
|
81
|
-
currentlyOpen
|
|
166
|
+
if (currentlyOpen) close();
|
|
167
|
+
else open();
|
|
82
168
|
}
|
|
83
169
|
|
|
170
|
+
// Now this is reactive!
|
|
84
171
|
export function isOpen() {
|
|
85
172
|
return currentlyOpen;
|
|
86
173
|
}
|
|
87
|
-
|
|
88
|
-
// TODO: this is kinda hacky
|
|
89
|
-
$effect(() => {
|
|
90
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
91
|
-
[popover, target];
|
|
92
|
-
postion(currentlyOpen);
|
|
93
|
-
});
|
|
94
174
|
</script>
|
|
95
175
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
A popover, positions itself relative to a target element.
|
|
99
|
-
-->
|
|
100
|
-
{#if currentlyOpen}
|
|
101
|
-
<div
|
|
102
|
-
class={twMerge(clsx('absolute', theme.current.popover?.class, clazz))}
|
|
103
|
-
style={style + ' ' + externalStyle}
|
|
104
|
-
bind:this={popover}
|
|
105
|
-
{@attach clickOutside({ callback: onClickOutside, target })}
|
|
106
|
-
{...rest}
|
|
107
|
-
>
|
|
176
|
+
<div bind:this={popoverEl} {style} {popover} class="bg-transparent">
|
|
177
|
+
<div class={twMerge(clsx(theme.current.popover?.class, clazz))} style={externalStyle} {...rest}>
|
|
108
178
|
{@render children?.()}
|
|
109
179
|
</div>
|
|
110
|
-
|
|
180
|
+
</div>
|