wx-svelte-menu 2.2.0 → 2.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.
package/license.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 XB Software Sp. z o.o.
3
+ Copyright (c) 2025 XB Software Sp. z o.o.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wx-svelte-menu",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Svelte menu component for creating dropdown menus, context menus, or complex menu bars",
5
5
  "productTag": "menu",
6
6
  "productTrial": false,
@@ -18,7 +18,8 @@
18
18
  "svelte": "src/index.js",
19
19
  "exports": {
20
20
  ".": {
21
- "svelte": "./src/index.js"
21
+ "svelte": "./src/index.js",
22
+ "types": "./types/index.d.ts"
22
23
  },
23
24
  "./package.json": "./package.json"
24
25
  },
@@ -32,11 +33,12 @@
32
33
  },
33
34
  "homepage": "https://svar.dev/svelte/core/",
34
35
  "dependencies": {
35
- "wx-svelte-core": "2.2.0",
36
- "wx-lib-dom": "0.9.1"
36
+ "@svar-ui/svelte-core": "2.3.1",
37
+ "@svar-ui/lib-dom": "0.9.2"
37
38
  },
38
39
  "files": [
39
40
  "src",
41
+ "types",
40
42
  "readme.md",
41
43
  "whatsnew.md",
42
44
  "license.txt"
package/readme.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  # SVAR Svelte Menu
4
4
 
5
- [![npm](https://img.shields.io/npm/v/wx-svelte-menu.svg)](https://www.npmjs.com/package/wx-svelte-menu)
5
+ [![npm](https://img.shields.io/npm/v/@svar-ui/svelte-menu.svg)](https://www.npmjs.com/package/@svar-ui/svelte-menu)
6
6
  [![License](https://img.shields.io/github/license/svar-widgets/menu)](https://github.com/svar-widgets/menu/blob/main/license.txt)
7
- [![npm downloads](https://img.shields.io/npm/dm/wx-svelte-menu.svg)](https://www.npmjs.com/package/wx-svelte-menu)
7
+ [![npm downloads](https://img.shields.io/npm/dm/@svar-ui/svelte-menu.svg)](https://www.npmjs.com/package/@svar-ui/svelte-menuu)
8
8
 
9
9
  </div>
10
10
 
@@ -14,7 +14,6 @@
14
14
 
15
15
  </div>
16
16
 
17
-
18
17
  SVAR Menu is a ready to use Svelte component for creating context and popup menus. Easily customize each menu item with text, icons, and sub-items, and control the menu's position relative to its parent element.
19
18
 
20
19
  ### How to Use
@@ -23,11 +22,10 @@ To use SVAR Svelte Menu, simply import the package and include the component in
23
22
 
24
23
  ```svelte
25
24
  <script>
26
- import { Menu } from "wx-svelte-menu";
25
+ import { Menu } from "@svar-ui/svelte-menu";
27
26
 
28
- function onClick(item) {
29
- const action = ev.detail.action;
30
- message = action ? `clicked on ${action.id}` : "closed";
27
+ function onClick(ev) {
28
+ message = ev.option ? `clicked on ${ev.option.id}` : "closed";
31
29
  }
32
30
 
33
31
  const options = [
@@ -41,7 +39,7 @@ To use SVAR Svelte Menu, simply import the package and include the component in
41
39
  ];
42
40
  </script>
43
41
 
44
- <Menu {options} on:click={clicked} />
42
+ <Menu {options} onclick={onClick} />
45
43
  ```
46
44
 
47
45
  For more details, visit the [documentation](https://docs.svar.dev/svelte/core/category/menu).
@@ -68,4 +66,4 @@ To run the test:
68
66
 
69
67
  ### Need Help?
70
68
 
71
- Join our [community forum](https://forum.svar.dev/) to get help or post feature requests.
69
+ Join our [community forum](https://forum.svar.dev/) to get help or post feature requests.
@@ -1,6 +1,6 @@
1
1
  <script>
2
- import { Portal } from "wx-svelte-core";
3
- import { id } from "wx-lib-dom";
2
+ import { Portal } from "@svar-ui/svelte-core";
3
+ import { id } from "@svar-ui/lib-dom";
4
4
  import Menu from "./Menu.svelte";
5
5
  import { filterMenu } from "../helpers";
6
6
 
@@ -21,7 +21,7 @@
21
21
 
22
22
  {#if children}
23
23
  <!-- svelte-ignore a11y_no_static_element_interactions -->
24
- <span oncontextmenu={menu.show} data-menu-ignore="true">
24
+ <span oncontextmenu={show} data-menu-ignore="true">
25
25
  {@render children?.()}
26
26
  </span>
27
27
  {/if}
@@ -1,20 +1,20 @@
1
1
  <script>
2
- import { Portal } from "wx-svelte-core";
2
+ import { Portal } from "@svar-ui/svelte-core";
3
3
  import Menu from "./Menu.svelte";
4
4
 
5
5
  let { options, at = "bottom", css = "", children, onclick } = $props();
6
6
 
7
- export const handler = ev => {
7
+ export function show(ev) {
8
8
  parent = ev.target;
9
9
  ev.preventDefault();
10
- };
10
+ }
11
11
 
12
12
  var parent = $state(null);
13
13
  function onClick(ev) {
14
14
  parent = null;
15
15
  onclick && onclick(ev);
16
16
  }
17
- function show(ev) {
17
+ function showAt(ev) {
18
18
  let target = ev.target;
19
19
  while (!target.dataset.menuIgnore) {
20
20
  parent = target;
@@ -25,7 +25,7 @@
25
25
 
26
26
  <!-- svelte-ignore a11y_click_events_have_key_events -->
27
27
  <!-- svelte-ignore a11y_no_static_element_interactions -->
28
- <span onclick={show} data-menu-ignore="true">
28
+ <span onclick={showAt} data-menu-ignore="true">
29
29
  {@render children?.()}
30
30
  </span>
31
31
  {#if parent}
@@ -1,10 +1,10 @@
1
1
  <script>
2
2
  import Menu from "./Menu.svelte";
3
3
 
4
- import { clickOutside, calculatePosition } from "wx-lib-dom";
4
+ import { clickOutside, calculatePosition } from "@svar-ui/lib-dom";
5
5
  import { onMount } from "svelte";
6
6
 
7
- import MenuItem from "./MenuItem.svelte";
7
+ import MenuOption from "./MenuOption.svelte";
8
8
  import { prepareMenuData } from "../helpers";
9
9
 
10
10
  let {
@@ -26,7 +26,7 @@
26
26
 
27
27
  let self = $state();
28
28
  let showSub = $state(false);
29
- let activeItem = $state(null);
29
+ let activeOption = $state(null);
30
30
 
31
31
  function updatePosition() {
32
32
  const result = calculatePosition(self, parent, at, left, top);
@@ -48,7 +48,12 @@
48
48
  showSub = false;
49
49
  }
50
50
  function cancel() {
51
- onclick && onclick({ action: null });
51
+ //[deprecated] action will be deprecated in 3.0
52
+ onclick && onclick({ action: null, option: null });
53
+ }
54
+ function onshow(id, el) {
55
+ showSub = id;
56
+ activeOption = el;
52
57
  }
53
58
 
54
59
  const finalOptions = $derived(prepareMenuData(options));
@@ -66,18 +71,23 @@
66
71
  style="position:absolute;top:{y}px;left:{x}px;width:{width};z-index:{z}"
67
72
  onmouseleave={onLeave}
68
73
  >
69
- {#each finalOptions as item (item.id)}
70
- {#if item.type === "separator"}
74
+ {#each finalOptions as option (option.id)}
75
+ {#if option.comp === "separator"}
71
76
  <div class="wx-separator"></div>
72
77
  {:else}
73
- <MenuItem
74
- {item}
75
- bind:showSub
76
- bind:activeItem
78
+ <MenuOption
79
+ {option}
80
+ {onshow}
77
81
  onclick={ev => {
78
- if (!item.data && !ev.defaultPrevented) {
79
- const pack = { context, action: item, event: ev };
80
- if (item.handler) item.handler(pack);
82
+ if (!option.data && !ev.defaultPrevented) {
83
+ //[deprecated] action will be deprecated in 3.0
84
+ const pack = {
85
+ context,
86
+ action: option,
87
+ option,
88
+ event: ev,
89
+ };
90
+ if (option.handler) option.handler(pack);
81
91
  onclick && onclick(pack);
82
92
 
83
93
  // it is a rare case when we need to stop event bubbling
@@ -87,12 +97,12 @@
87
97
  }}
88
98
  />
89
99
  {/if}
90
- {#if item.data && showSub === item.id}
100
+ {#if option.data && showSub === option.id}
91
101
  <Menu
92
102
  {css}
93
- options={item.data}
103
+ options={option.data}
94
104
  at="right-overlap"
95
- parent={activeItem}
105
+ parent={activeOption}
96
106
  {context}
97
107
  {onclick}
98
108
  />
@@ -7,7 +7,7 @@
7
7
 
8
8
  const finalOptions = $derived(prepareMenuData(options));
9
9
 
10
- let active = $state();
10
+ let active = $state(false);
11
11
  let menuOptions = $state([]);
12
12
 
13
13
  function doClick(ev) {
@@ -15,23 +15,24 @@
15
15
  onclick && onclick(ev);
16
16
  }
17
17
 
18
- function setMenu(ev, item, trigger) {
19
- // if the item has a submenu, show it and enable hover mode
20
- if (item.data && item.data.length) {
18
+ function setMenu(ev, option, trigger) {
19
+ // if the option has a submenu, show it and enable hover mode
20
+ if (option.data && option.data.length) {
21
21
  if (active && trigger) {
22
- // second click on item with submenu disables hover mode
22
+ // second click on option with submenu disables hover mode
23
23
  active = null;
24
24
  } else {
25
- menuOptions = item.data;
26
- active = item.id;
27
- menu.show(ev, item);
25
+ menuOptions = option.data;
26
+ active = option.id;
27
+ menu.show(ev, option);
28
28
  }
29
29
  } else {
30
30
  // hide the submenu
31
31
  menu.show(null);
32
32
  // if it was the click action, dispatch it and end hover mode
33
33
  if (trigger) {
34
- onclick && onclick({ action: item });
34
+ //[deprecated] action will be deprecated in 3.0
35
+ onclick && onclick({ action: option, option });
35
36
  active = null;
36
37
  } else {
37
38
  // do not remove active flag, to preserve the hover mode
@@ -40,17 +41,17 @@
40
41
  }
41
42
  }
42
43
 
43
- function onHover(ev, item) {
44
- if (active) setMenu(ev, item);
44
+ function onHover(ev, option) {
45
+ if (active) setMenu(ev, option);
45
46
  }
46
47
  </script>
47
48
 
48
49
  <div class="wx-menubar {css}">
49
- {#each finalOptions as item (item.id)}
50
+ {#each finalOptions as option (option.id)}
50
51
  <button
51
- class="wx-item {active === item.id ? 'wx-active' : ''}"
52
- onmouseenter={ev => onHover(ev, item)}
53
- onclick={ev => setMenu(ev, item, true)}>{item.text}</button
52
+ class="wx-option {active === option.id ? 'wx-active' : ''}"
53
+ onmouseenter={ev => onHover(ev, option)}
54
+ onclick={ev => setMenu(ev, option, true)}>{option.text}</button
54
55
  >
55
56
  {/each}
56
57
  </div>
@@ -69,7 +70,7 @@
69
70
  width: fit-content;
70
71
  }
71
72
 
72
- .wx-item {
73
+ .wx-option {
73
74
  background-color: transparent;
74
75
  border: none;
75
76
  color: var(--wx-color-font);
@@ -87,7 +88,7 @@
87
88
  }
88
89
 
89
90
  .wx-active,
90
- .wx-item:hover {
91
+ .wx-option:hover {
91
92
  background-color: var(--wx-background-alt);
92
93
  border-radius: var(--wx-button-border-radius);
93
94
  }
@@ -1,39 +1,35 @@
1
1
  <script>
2
2
  import { getItemHandler } from "../helpers";
3
3
 
4
- let {
5
- item,
6
- showSub = $bindable(false),
7
- activeItem = $bindable(null),
8
- onclick,
9
- } = $props();
4
+ let { option, onclick, onshow } = $props();
10
5
 
6
+ let element;
11
7
  function onHover() {
12
- showSub = item.data ? item.id : false;
13
- // eslint-disable-next-line @typescript-eslint/no-this-alias
14
- activeItem = this;
8
+ onshow(option.data ? option.id : false, element);
15
9
  }
16
10
  </script>
17
11
 
18
12
  <!-- svelte-ignore a11y_click_events_have_key_events -->
19
13
  <!-- svelte-ignore a11y_no_static_element_interactions -->
20
14
  <div
21
- class="wx-item {item.css || ''}"
22
- data-id={item.id}
15
+ bind:this={element}
16
+ class="wx-option {option.css || ''}"
17
+ data-id={option.id}
23
18
  onmouseenter={onHover}
24
19
  {onclick}
25
20
  >
26
- {#if item.icon}<i class="wx-icon {item.icon}"></i>{/if}
27
- {#if item.type}
28
- {@const SvelteComponent = getItemHandler(item.type)}
29
- <SvelteComponent {item} />
30
- {:else}<span class="wx-value"> {item.text} </span>{/if}
31
- {#if item.subtext}<span class="wx-subtext">{item.subtext}</span>{/if}
32
- {#if item.data}<i class="wx-sub-icon wxi-angle-right"></i>{/if}
21
+ {#if option.icon}<i class="wx-icon {option.icon}"></i>{/if}
22
+ {#if option.comp}
23
+ {@const SvelteComponent = getItemHandler(option.comp)}
24
+ <!-- [deprecated] item property will be deprecated in 3.0-->
25
+ <SvelteComponent item={option} {option} />
26
+ {:else}<span class="wx-value"> {option.text} </span>{/if}
27
+ {#if option.subtext}<span class="wx-subtext">{option.subtext}</span>{/if}
28
+ {#if option.data}<i class="wx-sub-icon wxi-angle-right"></i>{/if}
33
29
  </div>
34
30
 
35
31
  <style>
36
- .wx-item {
32
+ .wx-option {
37
33
  display: flex;
38
34
  align-items: center;
39
35
  box-sizing: border-box;
@@ -47,16 +43,16 @@
47
43
  cursor: pointer;
48
44
  }
49
45
 
50
- .wx-item:hover {
46
+ .wx-option:hover {
51
47
  background: var(--wx-background-alt);
52
48
  }
53
49
 
54
- .wx-item:first-child {
50
+ .wx-option:first-child {
55
51
  border-top-left-radius: inherit;
56
52
  border-top-right-radius: inherit;
57
53
  }
58
54
 
59
- .wx-item:last-child {
55
+ .wx-option:last-child {
60
56
  border-bottom-left-radius: inherit;
61
57
  border-bottom-right-radius: inherit;
62
58
  }
@@ -30,13 +30,15 @@ export function filterMenu(data, cb) {
30
30
  let uid = 1;
31
31
  export function prepareMenuData(data) {
32
32
  return mapData(data, a => {
33
+ // [deprecated] option.type to be deprecated in 3.0
34
+ if (a.type) a.comp = a.type;
33
35
  return { ...a, id: a.id || uid++ };
34
36
  });
35
37
  }
36
38
 
37
39
  const handlers = {};
38
40
  export function getItemHandler(type) {
39
- return handlers[type];
41
+ return handlers[type] || type;
40
42
  }
41
43
  export function registerMenuItem(type, handler) {
42
44
  handlers[type] = handler;
@@ -0,0 +1,74 @@
1
+ import type { Component } from "svelte";
2
+
3
+ export interface IMenuOption {
4
+ id?: string | number;
5
+ text?: string;
6
+ subtext?: string;
7
+ handler?: (ev: IMenuOptionClick) => void;
8
+ data?: IMenuOption[];
9
+ css?: string;
10
+ icon?: string;
11
+ type?: string | Component<any>; // @deprecated use `comp` instead. Will be removed in v3.0
12
+ comp?: string | Component<any>;
13
+ }
14
+
15
+ export interface IMenuOptionClick {
16
+ context?: any;
17
+ action: IMenuOption; // @deprecated use `option` instead. Will be removed in v3.0
18
+ option: IMenuOption;
19
+ event?: MouseEvent;
20
+ }
21
+
22
+ export declare const Menu: Component<{
23
+ options?: IMenuOption[];
24
+ left?: number;
25
+ top?: number;
26
+ at?: string;
27
+ parent?: HTMLElement;
28
+ mount?: (callback: () => void) => void;
29
+ context?: any;
30
+ css?: string;
31
+ onclick?: (ev: IMenuOptionClick) => void;
32
+ }>;
33
+
34
+ export declare const MenuBar: Component<{
35
+ css?: string;
36
+ menuCss?: string;
37
+ options?: IMenuOption[];
38
+ onclick?: (ev: IMenuOptionClick) => void;
39
+ }>;
40
+
41
+ export declare const DropDownMenu: Component<{
42
+ options?: IMenuOption[];
43
+ at?: string;
44
+ css?: string;
45
+ children?: () => any;
46
+ onclick?: (ev: IMenuOptionClick) => void;
47
+ }>;
48
+
49
+ export declare const ContextMenu: Component<{
50
+ options?: IMenuOption[];
51
+ at?: string;
52
+ resolver?: (item: any, event: MouseEvent) => any;
53
+ dataKey?: string;
54
+ filter?: (option: IMenuOption, item: any) => boolean;
55
+ css?: string;
56
+ children?: () => any;
57
+ onclick?: (ev: IMenuOptionClick) => void;
58
+ }>;
59
+
60
+ export declare const ActionMenu: Component<{
61
+ options?: IMenuOption[];
62
+ at?: string;
63
+ resolver?: (item: any, event: MouseEvent) => any;
64
+ dataKey?: string;
65
+ filter?: (option: IMenuOption, item: any) => boolean;
66
+ css?: string;
67
+ children?: () => any;
68
+ onclick?: (ev: IMenuOptionClick) => void;
69
+ }>;
70
+
71
+ export declare function registerMenuItem(
72
+ type: string,
73
+ handler: Component<{ option?: any }>
74
+ ): void;
package/whatsnew.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## 2.3.0
2
+
3
+ ### New features
4
+
5
+ - TypeScript definitions
6
+
7
+ ### Updates
8
+
9
+ API changes with backward compatibility until 3.0
10
+
11
+ - `onclick` event of all menus: `action` parameter is renamed to `option`
12
+ - Option `type` property is renamed to `comp`
13
+ - Property `item` of a custom component, registered as menu option, is renamed to `option`
14
+
15
+ ## 2.2.1
16
+
17
+ ### Fixes
18
+
19
+ - Using in Salesforce environment
20
+
1
21
  ## 2.2.0
2
22
 
3
23
  - Using core@2.2.0