svseeds 0.4.9 → 0.4.10

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.
@@ -34,7 +34,6 @@
34
34
 
35
35
  const preset = "svs-combo-box";
36
36
  const NA = -1;
37
- const optionStyle = "cursor: default; user-select: none;";
38
37
 
39
38
  import { type Snippet } from "svelte";
40
39
  import { type Action } from "svelte/action";
@@ -56,7 +55,7 @@
56
55
  let listElem: HTMLUListElement | undefined = $state();
57
56
 
58
57
  // *** Bind Handlers *** //
59
- let listboxStyle = $derived(`position:absolute;visibility: ${expanded ? "visible" : "hidden"};${overflow.x ? "right:0%;" : ""}${overflow.y ? "bottom:100%;" : ""}`);
58
+ let listboxStyle = $derived(`position:absolute;cursor:default;user-select:none;visibility: ${expanded ? "visible" : "hidden"};${overflow.x ? "right:0%;" : ""}${overflow.y ? "bottom:100%;" : ""}`);
60
59
  let opts = $derived([...options.keys()]);
61
60
  let maxlen = $derived(opts.reduce((max, x) => Math.max(max, [...x].length), 0));
62
61
 
@@ -133,7 +132,7 @@
133
132
  <input bind:value bind:this={element} class={cls(PARTS.MAIN, variant)} type="text" role="combobox" aria-haspopup="listbox" aria-autocomplete="none" aria-controls={idList} aria-expanded={expanded} onfocus={() => open()} onblur={close} {onkeydown} {oninput} {...attrs} />
134
133
  {/if}
135
134
  {#if extra}
136
- <div class={cls(PARTS.EXTRA, variant)} style="position:absolute;margin:auto 0;top:0%;right:0%;">
135
+ <div class={cls(PARTS.EXTRA, variant)} style="position:absolute;top:50%;right:0%;transform:translateY(-50%);pointer-events:none;">
137
136
  {@render extra(expanded, variant)}
138
137
  </div>
139
138
  {/if}
@@ -142,7 +141,7 @@
142
141
  {@const isSelected = i === selected}
143
142
  {@const labelStatus = isSelected ? VARIANT.ACTIVE : variant}
144
143
  {@const onpointerenter = () => selected = i}
145
- <li class={cls(PARTS.LABEL, labelStatus)} aria-selected={isSelected} role="option" style={optionStyle} onpointerdown={apply} {onpointerenter}>
144
+ <li class={cls(PARTS.LABEL, labelStatus)} aria-selected={isSelected} role="option" onpointerdown={apply} {onpointerenter}>
146
145
  {opt}
147
146
  </li>
148
147
  {/each}
@@ -6,6 +6,7 @@
6
6
  children: Snippet<[string]>; // Snippet<[variant]>
7
7
  open?: boolean; // bindable (false); to observe state, not to control
8
8
  lock?: boolean; // bindable (false)
9
+ target?: HTMLElement;
9
10
  element?: HTMLElement; // bindable
10
11
  styling?: SVSClass;
11
12
  variant?: string; // bindable (VARIANT.NEUTRAL)
@@ -17,6 +18,7 @@
17
18
  children: Snippet<[string]>; // Snippet<[variant]>
18
19
  open?: boolean; // bindable (false); to observe state, not to control
19
20
  lock?: boolean; // bindable (false)
21
+ target?: HTMLElement;
20
22
  element?: HTMLElement; // bindable
21
23
  styling?: SVSClass;
22
24
  variant?: string; // bindable (VARIANT.NEUTRAL)
@@ -26,39 +28,47 @@
26
28
 
27
29
  const preset = "svs-context-menu";
28
30
 
29
- import { type Snippet } from "svelte";
31
+ import { type Snippet, onDestroy } from "svelte";
32
+ import { on } from "svelte/events";
30
33
  import { type SVSClass, VARIANT, PARTS, fnClass } from "./core";
31
34
  </script>
32
35
 
33
36
  <!---------------------------------------->
34
37
 
35
38
  <script lang="ts">
36
- let { children, open = $bindable(false), lock = $bindable(false), element = $bindable(), styling, variant = $bindable("") }: ContextMenuProps = $props();
39
+ let { children, open = $bindable(false), lock = $bindable(false), target, element = $bindable(), styling, variant = $bindable("") }: ContextMenuProps = $props();
37
40
 
38
41
  // *** Initialize *** //
39
42
  if (!variant) variant = VARIANT.NEUTRAL;
40
43
  const cls = fnClass(preset, styling);
41
44
  let position = $state({ x: 0, y: 0 });
45
+ let listeners: (() => void)[] = [];
46
+ $effect(() => {
47
+ listeners.push(on(target ?? document, "contextmenu", show));
48
+ if (target) listeners.push(on(document, "contextmenu", hide));
49
+ });
50
+ onDestroy(() => listeners.forEach((x) => x()));
42
51
 
43
52
  // *** Bind Handlers *** //
44
- let visibility = $derived(open ? "visibility: visible;" : "visibility: hidden; z-index: -9999;");
45
- let dynStyle = $derived(`position: fixed; left:${position.x}px; top:${position.y}px; ${visibility}`);
53
+ let dynStyle = $derived(`position:fixed;left:${position.x}px;top:${position.y}px;${open ? "visibility:visible;" : "visibility:hidden;z-index:-9999;"}`);
46
54
 
47
55
  // *** Event Handlers *** //
48
- function show(ev: MouseEvent) {
56
+ function show(ev: Event) {
49
57
  if (lock) return;
50
58
  ev.preventDefault();
59
+ ev.stopPropagation();
51
60
 
61
+ const [x, y] = [(ev as MouseEvent).clientX, (ev as MouseEvent).clientY];
52
62
  const menu = { width: element?.offsetWidth ?? 0, height: element?.offsetHeight ?? 0 };
53
- position.x = window.innerWidth-ev.clientX < menu.width ? ev.clientX-menu.width : ev.clientX;
54
- position.y = window.innerHeight-ev.clientY < menu.height ? (ev.clientY < menu.height ? ev.clientY : ev.clientY-menu.height) : ev.clientY;
63
+ position.x = window.innerWidth-x < menu.width ? x-menu.width : x;
64
+ position.y = window.innerHeight-y < menu.height ? (y < menu.height ? y : y-menu.height) : y;
55
65
  open = true;
56
66
  }
57
67
  function hide() { if (!lock) open = false; }
58
68
  </script>
59
69
 
60
70
  <!---------------------------------------->
61
- <svelte:document oncontextmenu={show} onclick={hide} />
71
+ <svelte:document onclick={hide} />
62
72
 
63
73
  <nav class={cls(PARTS.WHOLE, variant)} style={dynStyle} bind:this={element}>
64
74
  {@render children(variant)}
@@ -2,6 +2,7 @@ export interface ContextMenuProps {
2
2
  children: Snippet<[string]>;
3
3
  open?: boolean;
4
4
  lock?: boolean;
5
+ target?: HTMLElement;
5
6
  element?: HTMLElement;
6
7
  styling?: SVSClass;
7
8
  variant?: string;
@@ -17,6 +18,7 @@ import { type SVSClass } from "./core";
17
18
  * children: Snippet<[string]>; // Snippet<[variant]>
18
19
  * open?: boolean; // bindable (false); to observe state, not to control
19
20
  * lock?: boolean; // bindable (false)
21
+ * target?: HTMLElement;
20
22
  * element?: HTMLElement; // bindable
21
23
  * styling?: SVSClass;
22
24
  * variant?: string; // bindable (VARIANT.NEUTRAL)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svseeds",
3
- "version": "0.4.9",
3
+ "version": "0.4.10",
4
4
  "description": "Simple components for Svelte.",
5
5
  "type": "module",
6
6
  "main": "./index.js",