@axium/client 0.13.4 → 0.14.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/assets/styles.css +14 -0
- package/lib/Popover.svelte +0 -15
- package/lib/Upload.svelte +2 -3
- package/lib/attachments.ts +92 -0
- package/lib/index.ts +0 -1
- package/package.json +2 -1
- package/lib/WithContextMenu.svelte +0 -73
package/assets/styles.css
CHANGED
|
@@ -221,6 +221,20 @@ input.error {
|
|
|
221
221
|
gap: 0.1em;
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
[popover] .menu-item {
|
|
225
|
+
display: inline-flex;
|
|
226
|
+
align-items: center;
|
|
227
|
+
padding: 0.5em 0.75em;
|
|
228
|
+
gap: 1em;
|
|
229
|
+
border-radius: 0.5em;
|
|
230
|
+
user-select: none;
|
|
231
|
+
|
|
232
|
+
&:hover {
|
|
233
|
+
background-color: var(--bg-strong);
|
|
234
|
+
cursor: pointer;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
224
238
|
.icon-text {
|
|
225
239
|
display: inline-flex;
|
|
226
240
|
align-items: center;
|
package/lib/Popover.svelte
CHANGED
|
@@ -11,8 +11,6 @@
|
|
|
11
11
|
}
|
|
12
12
|
</script>
|
|
13
13
|
|
|
14
|
-
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
15
|
-
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
16
14
|
<div {onclick}>
|
|
17
15
|
{#if toggle}
|
|
18
16
|
{@render toggle()}
|
|
@@ -55,17 +53,4 @@
|
|
|
55
53
|
left: anchor(left);
|
|
56
54
|
top: anchor(bottom);
|
|
57
55
|
}
|
|
58
|
-
|
|
59
|
-
[popover] :global(.menu-item) {
|
|
60
|
-
display: inline-flex;
|
|
61
|
-
align-items: center;
|
|
62
|
-
padding: 0.5em 0.75em;
|
|
63
|
-
gap: 1em;
|
|
64
|
-
border-radius: 0.5em;
|
|
65
|
-
|
|
66
|
-
&:hover {
|
|
67
|
-
background-color: var(--bg-strong);
|
|
68
|
-
cursor: pointer;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
56
|
</style>
|
package/lib/Upload.svelte
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
let {
|
|
7
7
|
name = 'files',
|
|
8
|
-
input = $bindable(),
|
|
9
8
|
files = $bindable(),
|
|
10
9
|
progress = $bindable([]),
|
|
11
10
|
...rest
|
|
@@ -27,7 +26,7 @@
|
|
|
27
26
|
e.preventDefault();
|
|
28
27
|
const dt = new DataTransfer();
|
|
29
28
|
for (let f of files!) if (file !== f) dt.items.add(f);
|
|
30
|
-
|
|
29
|
+
files = dt.files;
|
|
31
30
|
}}
|
|
32
31
|
style:display="contents"
|
|
33
32
|
>
|
|
@@ -50,7 +49,7 @@
|
|
|
50
49
|
{/each}
|
|
51
50
|
</label>
|
|
52
51
|
|
|
53
|
-
<input bind:
|
|
52
|
+
<input bind:files {name} {id} type="file" {...rest} />
|
|
54
53
|
</div>
|
|
55
54
|
|
|
56
55
|
<style>
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelte attachments
|
|
3
|
+
* @see https://svelte.dev/docs/svelte/@attach
|
|
4
|
+
*/
|
|
5
|
+
import { mount, unmount } from 'svelte';
|
|
6
|
+
import Icon from './Icon.svelte';
|
|
7
|
+
import type { Attachment } from 'svelte/attachments';
|
|
8
|
+
|
|
9
|
+
export interface ContextMenuItem {
|
|
10
|
+
/** Icon name */
|
|
11
|
+
i?: string;
|
|
12
|
+
text: string;
|
|
13
|
+
danger?: boolean;
|
|
14
|
+
action(): unknown;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Attach a context menu to an element with the given actions
|
|
19
|
+
*/
|
|
20
|
+
export function contextMenu(...menuItems: ContextMenuItem[]) {
|
|
21
|
+
function _attachContextMenu(element: HTMLElement) {
|
|
22
|
+
const menu = document.createElement('div');
|
|
23
|
+
menu.popover = 'auto';
|
|
24
|
+
menu.className = 'context-menu';
|
|
25
|
+
|
|
26
|
+
const mountedIcons = new Set<Record<string, any>>();
|
|
27
|
+
|
|
28
|
+
for (const item of menuItems) {
|
|
29
|
+
const div = document.createElement('div');
|
|
30
|
+
div.classList.add('icon-text', 'menu-item');
|
|
31
|
+
if (item.danger) div.classList.add('danger');
|
|
32
|
+
|
|
33
|
+
div.onclick = e => {
|
|
34
|
+
e.stopPropagation();
|
|
35
|
+
menu.hidePopover();
|
|
36
|
+
item.action();
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
if (item.i) mountedIcons.add(mount<any, {}>(Icon, { target: div, props: { i: item.i } }));
|
|
40
|
+
|
|
41
|
+
div.appendChild(document.createTextNode(item.text));
|
|
42
|
+
|
|
43
|
+
menu.appendChild(div);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
document.body.appendChild(menu);
|
|
47
|
+
|
|
48
|
+
let _forcePopover = false;
|
|
49
|
+
|
|
50
|
+
element.oncontextmenu = (e: MouseEvent) => {
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
e.stopPropagation();
|
|
53
|
+
|
|
54
|
+
menu.showPopover();
|
|
55
|
+
_forcePopover = true;
|
|
56
|
+
|
|
57
|
+
const x = e.clientX;
|
|
58
|
+
const y = e.clientY;
|
|
59
|
+
|
|
60
|
+
menu.style.left = x + 'px';
|
|
61
|
+
menu.style.top = y + 'px';
|
|
62
|
+
|
|
63
|
+
const rect = menu.getBoundingClientRect();
|
|
64
|
+
if (rect.right > window.innerWidth) {
|
|
65
|
+
menu.style.left = '';
|
|
66
|
+
menu.style.right = window.innerWidth - x + 'px';
|
|
67
|
+
}
|
|
68
|
+
if (rect.bottom > window.innerHeight) {
|
|
69
|
+
menu.style.top = '';
|
|
70
|
+
menu.style.bottom = window.innerHeight - y + 'px';
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Workaround for https://github.com/whatwg/html/issues/10905
|
|
76
|
+
* @todo Remove when the problem is fixed.
|
|
77
|
+
*/
|
|
78
|
+
element.onpointerup = (e: PointerEvent) => {
|
|
79
|
+
if (!_forcePopover) return;
|
|
80
|
+
e.stopPropagation();
|
|
81
|
+
e.preventDefault();
|
|
82
|
+
menu.togglePopover();
|
|
83
|
+
_forcePopover = false;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
return function _disposeContextMenu() {
|
|
87
|
+
for (const icon of mountedIcons) unmount(icon);
|
|
88
|
+
menu.remove();
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return _attachContextMenu satisfies Attachment<HTMLElement>;
|
|
92
|
+
}
|
package/lib/index.ts
CHANGED
|
@@ -16,6 +16,5 @@ export { default as URLText } from './URLText.svelte';
|
|
|
16
16
|
export { default as UserCard } from './UserCard.svelte';
|
|
17
17
|
export { default as UserMenu } from './UserMenu.svelte';
|
|
18
18
|
export { default as Version } from './Version.svelte';
|
|
19
|
-
export { default as WithContextMenu } from './WithContextMenu.svelte';
|
|
20
19
|
export { default as ZodForm } from './ZodForm.svelte';
|
|
21
20
|
export { default as ZodInput } from './ZodInput.svelte';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axium/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"author": "James Prevett <jp@jamespre.dev>",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"./*": "./dist/*.js",
|
|
35
35
|
"./components": "./lib/index.js",
|
|
36
36
|
"./components/*": "./lib/*.svelte",
|
|
37
|
+
"./attachments": "./lib/attachments.js",
|
|
37
38
|
"./styles/*": "./styles/*.css"
|
|
38
39
|
},
|
|
39
40
|
"scripts": {
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
-
import Icon from './Icon.svelte';
|
|
4
|
-
|
|
5
|
-
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
6
|
-
children(): any;
|
|
7
|
-
menu(
|
|
8
|
-
/**
|
|
9
|
-
* Shortcut to quickly create a generic action in the context menu.
|
|
10
|
-
*/
|
|
11
|
-
action: (icon: string, text: string, action: (event: MouseEvent) => void) => any
|
|
12
|
-
): any;
|
|
13
|
-
actions: Record<string, () => void>;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
let { children, menu, actions, ...rest }: Props = $props();
|
|
17
|
-
|
|
18
|
-
let popover = $state<HTMLDivElement>();
|
|
19
|
-
|
|
20
|
-
function oncontextmenu(e: MouseEvent) {
|
|
21
|
-
e.preventDefault();
|
|
22
|
-
e.stopPropagation();
|
|
23
|
-
popover!.togglePopover();
|
|
24
|
-
_forcePopover = true;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
let _forcePopover = false;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Workaround for https://github.com/whatwg/html/issues/10905
|
|
31
|
-
* @todo Remove when the problem is fixed.
|
|
32
|
-
*/
|
|
33
|
-
function onpointerup(e: PointerEvent) {
|
|
34
|
-
if (!_forcePopover) return;
|
|
35
|
-
e.stopPropagation();
|
|
36
|
-
e.preventDefault();
|
|
37
|
-
popover!.togglePopover();
|
|
38
|
-
_forcePopover = false;
|
|
39
|
-
}
|
|
40
|
-
</script>
|
|
41
|
-
|
|
42
|
-
{#snippet action(i: string, text: string, action: (event: MouseEvent) => void)}
|
|
43
|
-
<div
|
|
44
|
-
onclick={e => {
|
|
45
|
-
e.stopPropagation();
|
|
46
|
-
e.preventDefault();
|
|
47
|
-
action(e);
|
|
48
|
-
}}
|
|
49
|
-
class="action"
|
|
50
|
-
>
|
|
51
|
-
{#if i}<Icon {i} --size="14px" />{/if}
|
|
52
|
-
{text}
|
|
53
|
-
</div>
|
|
54
|
-
{/snippet}
|
|
55
|
-
|
|
56
|
-
<div data-axium-context-menu {oncontextmenu} {onpointerup} {...rest}>
|
|
57
|
-
{@render children()}
|
|
58
|
-
<div popover bind:this={popover}>
|
|
59
|
-
{@render menu(action)}
|
|
60
|
-
</div>
|
|
61
|
-
</div>
|
|
62
|
-
|
|
63
|
-
<style>
|
|
64
|
-
[data-axium-context-menu] {
|
|
65
|
-
display: contents;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
div.action:hover {
|
|
69
|
-
cursor: pointer;
|
|
70
|
-
background-color: var(--bg-strong);
|
|
71
|
-
border-radius: 0.25em;
|
|
72
|
-
}
|
|
73
|
-
</style>
|