aleman 1.0.17 → 1.1.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.
Files changed (95) hide show
  1. package/aleman/add-listeners.js +94 -0
  2. package/aleman/index.js +44 -0
  3. package/aleman/render.js +58 -0
  4. package/aleman/state.js +78 -0
  5. package/example/index.html +1 -0
  6. package/example/index.js +8 -0
  7. package/index-buttons.html +2 -2
  8. package/index.html +2 -3
  9. package/menu/addons/click.js +6 -0
  10. package/menu/addons/context-menu.js +13 -0
  11. package/menu/addons/down.js +16 -0
  12. package/menu/addons/enter.js +16 -0
  13. package/menu/addons/escape.js +6 -0
  14. package/menu/addons/f9.js +9 -0
  15. package/menu/addons/index.js +21 -0
  16. package/menu/addons/item-click.js +16 -0
  17. package/menu/addons/mouse-enter.js +5 -0
  18. package/menu/addons/up.js +12 -0
  19. package/menu/hydrate-menu.js +22 -0
  20. package/menu/importmap.json +9 -0
  21. package/menu/menu.js +40 -23
  22. package/{lib → menu}/rules/index.js +4 -10
  23. package/{lib → menu}/rules/select/fixture/select-fix.js +1 -1
  24. package/{lib → menu}/rules/select/index.js +29 -5
  25. package/menu/rules/set-position/fixture/no-style.js +2 -0
  26. package/menu/rules/set-position/fixture/set-position-fix.js +2 -0
  27. package/{lib → menu}/rules/set-position/index.js +29 -4
  28. package/{lib → menu}/rules/unselect-all/index.js +6 -1
  29. package/menu/state.js +15 -0
  30. package/package.json +3 -6
  31. package/lib/addons/additional/fixture/start-click-fix.html +0 -0
  32. package/lib/addons/additional/fixture/start-click.html +0 -1
  33. package/lib/addons/additional/fixture/stop-click-fix.html +0 -0
  34. package/lib/addons/additional/fixture/stop-click.html +0 -1
  35. package/lib/addons/additional/input-change.js +0 -39
  36. package/lib/addons/additional/start-click.js +0 -7
  37. package/lib/addons/additional/stop-click.js +0 -7
  38. package/lib/addons/menu-item-click.js +0 -27
  39. package/lib/addons/menu-mouse-over.js +0 -6
  40. package/lib/addons/show-menu-click.js +0 -11
  41. package/lib/aleman/add-listeners.js +0 -116
  42. package/lib/aleman/aleman.js +0 -47
  43. package/lib/aleman/load.js +0 -5
  44. package/lib/aleman/render.js +0 -107
  45. package/lib/globals/menu/click.js +0 -21
  46. package/lib/globals/menu/context-menu.js +0 -18
  47. package/lib/globals/menu/down.js +0 -21
  48. package/lib/globals/menu/enter.js +0 -33
  49. package/lib/globals/menu/escape.js +0 -19
  50. package/lib/globals/menu/f9.js +0 -27
  51. package/lib/globals/menu/menu.js +0 -34
  52. package/lib/globals/menu/up.js +0 -19
  53. package/lib/globals/menu.js +0 -17
  54. package/lib/main.js +0 -35
  55. package/lib/menu/menu.js +0 -4
  56. package/lib/rules/README.md +0 -10
  57. package/lib/rules/remove-button/fixture/remove-button-fix.js +0 -2
  58. package/lib/rules/remove-button/fixture/remove-button.js +0 -2
  59. package/lib/rules/remove-button/index.js +0 -27
  60. package/lib/rules/set-value/fixture/data-name.js +0 -1
  61. package/lib/rules/set-value/fixture/no-data-name.js +0 -1
  62. package/lib/rules/set-value/fixture/not-label.js +0 -1
  63. package/lib/rules/set-value/fixture/set-value-fix.js +0 -1
  64. package/lib/rules/set-value/fixture/set-value.js +0 -1
  65. package/lib/rules/set-value/index.js +0 -34
  66. package/lib/rules/unselect/fixture/no-data-name.js +0 -4
  67. package/lib/rules/unselect/fixture/no-parent.js +0 -2
  68. package/lib/rules/unselect/fixture/unselect-fix.js +0 -8
  69. package/lib/rules/unselect/fixture/unselect.js +0 -8
  70. package/lib/rules/unselect/index.js +0 -39
  71. package/menu/index.html +0 -4
  72. package/menu/main.js +0 -33
  73. /package/{lib → menu}/rules/build-menu/fixture/build-menu-fix.js +0 -0
  74. /package/{lib → menu}/rules/build-menu/fixture/build-menu.js +0 -0
  75. /package/{lib → menu}/rules/build-menu/fixture/built.js +0 -0
  76. /package/{lib → menu}/rules/build-menu/index.js +0 -0
  77. /package/{lib → menu}/rules/check-data-name.js +0 -0
  78. /package/{lib → menu}/rules/menu/fixture/hide-menu-fix.js +0 -0
  79. /package/{lib → menu}/rules/menu/fixture/hide-menu.js +0 -0
  80. /package/{lib → menu}/rules/menu/fixture/no-menu.js +0 -0
  81. /package/{lib → menu}/rules/menu/fixture/show-menu-fix.js +0 -0
  82. /package/{lib → menu}/rules/menu/fixture/show-menu.js +0 -0
  83. /package/{lib → menu}/rules/menu/index.js +0 -0
  84. /package/{lib → menu}/rules/select/fixture/no-data-name.js +0 -0
  85. /package/{lib → menu}/rules/select/fixture/no-next.js +0 -0
  86. /package/{lib → menu}/rules/select/fixture/no-parent.js +0 -0
  87. /package/{lib → menu}/rules/select/fixture/select.js +0 -0
  88. /package/{lib → menu}/rules/select/fixture/wrong-data-name.js +0 -0
  89. /package/{lib/rules/set-position/fixture/set-position-fix.js → menu/rules/set-position/fixture/no-style-fix.js} +0 -0
  90. /package/{lib → menu}/rules/set-position/fixture/not-menu.js +0 -0
  91. /package/{lib → menu}/rules/set-position/fixture/set-position.js +0 -0
  92. /package/{lib → menu}/rules/unselect-all/fixture/no-data-name.js +0 -0
  93. /package/{lib → menu}/rules/unselect-all/fixture/no-parent.js +0 -0
  94. /package/{lib → menu}/rules/unselect-all/fixture/unselect-all-fix.js +0 -0
  95. /package/{lib → menu}/rules/unselect-all/fixture/unselect-all.js +0 -0
@@ -0,0 +1,94 @@
1
+ const queryElement = ({name}) => {
2
+ return document.querySelector(`[data-name="${name}"]`);
3
+ };
4
+
5
+ const maybeEvents = ({events}) => {
6
+ if (events)
7
+ return events;
8
+
9
+ return ['keydown'];
10
+ };
11
+
12
+ export const addListeners = ({namedAddons, options, readState, writeState}) => {
13
+ for (const addon of namedAddons) {
14
+ const element = queryElement(addon);
15
+ const events = maybeEvents(addon);
16
+ const {
17
+ key,
18
+ listener,
19
+ preventDefault,
20
+ } = addon;
21
+
22
+ for (const event of events) {
23
+ element.addEventListener(event, (event) => {
24
+ if (preventDefault)
25
+ event.preventDefault();
26
+
27
+ if (key && event.key !== key)
28
+ return;
29
+
30
+ const state = readState();
31
+
32
+ const newState = listener({
33
+ event,
34
+ state,
35
+ options,
36
+ });
37
+
38
+ writeState(newState);
39
+ });
40
+ }
41
+ }
42
+ };
43
+
44
+ const hasName = ({name}) => name;
45
+
46
+ export const splitAddons = (addons) => {
47
+ const globalAddons = [];
48
+ const namedAddons = [];
49
+
50
+ for (const addon of addons) {
51
+ if (hasName(addon)) {
52
+ namedAddons.push(addon);
53
+ continue;
54
+ }
55
+
56
+ globalAddons.push(addon);
57
+ }
58
+
59
+ return {
60
+ globalAddons,
61
+ namedAddons,
62
+ };
63
+ };
64
+
65
+ export const addGlobalListeners = ({globalAddons, options, readState, writeState}) => {
66
+ for (const addon of globalAddons) {
67
+ const events = maybeEvents(addon);
68
+ const {
69
+ key,
70
+ listener,
71
+ preventDefault,
72
+ } = addon;
73
+
74
+ for (const event of events) {
75
+ document.addEventListener(event, (event) => {
76
+ if (preventDefault)
77
+ event.preventDefault();
78
+
79
+ if (key && event.key !== key)
80
+ return;
81
+
82
+ const state = readState();
83
+
84
+ const newState = listener({
85
+ event,
86
+ state,
87
+ options,
88
+ });
89
+
90
+ writeState(newState);
91
+ });
92
+ }
93
+ }
94
+ };
@@ -0,0 +1,44 @@
1
+ import {createState} from './state.js';
2
+ import {
3
+ addGlobalListeners,
4
+ addListeners,
5
+ splitAddons,
6
+ } from './add-listeners.js';
7
+ import {createRender} from './render.js';
8
+
9
+ export const hydrate = (element, {addons, options, state, rules, stateName = 'aleman-state'}) => {
10
+ const render = createRender(element.innerHTML, {
11
+ options,
12
+ rules,
13
+ });
14
+
15
+ const {globalAddons, namedAddons} = splitAddons(addons);
16
+
17
+ const listener = () => {
18
+ const state = readState();
19
+ const [is, result] = render(state);
20
+
21
+ if (!is)
22
+ return;
23
+
24
+ element.innerHTML = result;
25
+ addListeners({
26
+ readState,
27
+ writeState,
28
+ namedAddons,
29
+ options,
30
+ });
31
+ };
32
+
33
+ const {readState, writeState} = createState(state, {
34
+ stateName,
35
+ listener,
36
+ });
37
+
38
+ addGlobalListeners({
39
+ readState,
40
+ writeState,
41
+ globalAddons,
42
+ options,
43
+ });
44
+ };
@@ -0,0 +1,58 @@
1
+ import {
2
+ parse,
3
+ transform,
4
+ print,
5
+ findPlaces,
6
+ } from 'putout';
7
+ import {branch, merge} from '@putout/processor-html';
8
+
9
+ const {entries} = Object;
10
+
11
+ export const SKIP = false;
12
+ export const TRANSFORM = true;
13
+
14
+ export const createRender = (html, {options, rules}) => {
15
+ const {source} = branch(html)[0];
16
+ const withDiv = `<template>${source}</template>`;
17
+ const ast = parse(withDiv);
18
+
19
+ return function render(state) {
20
+ const currentRules = {};
21
+ const plugins = entries(rules);
22
+
23
+ for (const [name] of plugins) {
24
+ currentRules[name] = ['on', {
25
+ ...state,
26
+ ...options,
27
+ }];
28
+ }
29
+
30
+ const places = findPlaces(ast, source, {
31
+ rules: currentRules,
32
+ plugins,
33
+ });
34
+
35
+ if (!places.length)
36
+ return [SKIP];
37
+
38
+ transform(ast, '', {
39
+ rules: currentRules,
40
+ plugins,
41
+ });
42
+
43
+ const code = print(ast, {
44
+ printer: ['putout', {
45
+ format: {
46
+ newline: '',
47
+ endOfFile: '',
48
+ },
49
+ }],
50
+ });
51
+
52
+ const prefix = '<template>';
53
+ const suffix = '<\\template>\n';
54
+ const result = merge('', [code]).slice(prefix.length, -suffix.length);
55
+
56
+ return [TRANSFORM, result];
57
+ };
58
+ };
@@ -0,0 +1,78 @@
1
+ import fullstore from 'fullstore';
2
+
3
+ const {assign} = Object;
4
+ const {stringify, parse} = JSON;
5
+
6
+ const wrap = (render, {prev, options, stateElement, readState, writeState}) => () => {
7
+ const {textContent} = stateElement;
8
+
9
+ if (stateElement.textContent === prev())
10
+ return;
11
+
12
+ const state = readState();
13
+ prev(textContent);
14
+ writeState(state);
15
+
16
+ render({
17
+ state,
18
+ options,
19
+ });
20
+ };
21
+
22
+ export const createState = (state, {options, listener, stateName = 'aleman-state'}) => {
23
+ const stateElement = document.querySelector(`[data-name="${stateName}"]`);
24
+
25
+ const prev = fullstore();
26
+ const readState = createReadState(stateElement);
27
+ const writeState = createWriteState(prev, stateElement);
28
+
29
+ const fn = wrap(listener, {
30
+ options,
31
+ prev,
32
+ stateElement,
33
+ readState,
34
+ writeState,
35
+ });
36
+
37
+ const observer = new MutationObserver(fn);
38
+ const str = stringify(state, null, 4);
39
+
40
+ history[str] = true;
41
+ stateElement.textContent = str;
42
+
43
+ document.addEventListener('keydown', ({key}) => {
44
+ if (key === '`')
45
+ fn();
46
+ });
47
+
48
+ observer.observe(stateElement, {
49
+ attributes: true,
50
+ childList: true,
51
+ subtree: true,
52
+ });
53
+
54
+ return {
55
+ readState,
56
+ writeState,
57
+ };
58
+ };
59
+
60
+ export const createReadState = (stateElement) => () => {
61
+ return parse(stateElement.textContent);
62
+ };
63
+
64
+ export const createWriteState = (prev, stateElement) => (newState) => {
65
+ const prevStateStr = stateElement.textContent;
66
+ const prevState = parse(stateElement.textContent);
67
+
68
+ assign(prevState, newState);
69
+ const str = stringify(prevState);
70
+
71
+ if (str === prevStateStr)
72
+ return;
73
+
74
+ stateElement.textContent = str;
75
+ setTimeout(() => {
76
+ prev(str);
77
+ });
78
+ };
@@ -0,0 +1 @@
1
+ <script src="index.js" type="module"></script>
@@ -0,0 +1,8 @@
1
+ import {createMenu} from '../menu/menu.js';
2
+
3
+ const menuData = {
4
+ hello: () => alert('x'),
5
+ world: () => alert('y'),
6
+ };
7
+
8
+ await createMenu(document.body, {}, menuData);
@@ -1,5 +1,5 @@
1
1
  <!doctype html>
2
- <link href="menu/menu.css" rel="stylesheet">
2
+ <link href="menu-v1/menu.css" rel="stylesheet">
3
3
 
4
4
  <section data-name="hydrate">
5
5
  <button data-name="menu-toggler">Menu</button>
@@ -14,7 +14,7 @@
14
14
  </section>
15
15
 
16
16
 
17
- <script data-name="aleman" type="module" src="lib/aleman/load.js" data-main="lib/main.js"></script>
17
+ <script data-name="aleman" type="module" src="menu-v1/aleman/load.js" data-main="lib/main.js"></script>
18
18
  <script type="importmap">
19
19
  {
20
20
  "imports": {
package/index.html CHANGED
@@ -1,13 +1,12 @@
1
1
  <!doctype html>
2
- <link href="menu/menu.css" rel="stylesheet">
2
+ <link href="menu-v1/menu.css" rel="stylesheet">
3
3
 
4
4
  <section data-name="hydrate">
5
5
  <ul data-name="menu" class="menu menu-hidden" style="left: 0; top: 20px;">
6
6
  </ul>
7
7
  </section>
8
8
 
9
-
10
- <script data-name="aleman" type="module" src="lib/aleman/load.js"></script>
9
+ <script data-name="aleman" type="module" src="menu-v1/aleman/load.js"></script>
11
10
  <script type="importmap">
12
11
  {
13
12
  "imports": {
@@ -0,0 +1,6 @@
1
+ export const events = ['click'];
2
+
3
+ export const listener = () => ({
4
+ command: 'hide',
5
+ index: -1,
6
+ });
@@ -0,0 +1,13 @@
1
+ export const events = [
2
+ 'contextmenu',
3
+ ];
4
+
5
+ export const preventDefault = true;
6
+
7
+ export const listener = ({event}) => ({
8
+ command: 'show',
9
+ position: {
10
+ left: event.clientX,
11
+ top: event.clientY - 14,
12
+ },
13
+ });
@@ -0,0 +1,16 @@
1
+ const {keys} = Object;
2
+
3
+ export const key = 'ArrowDown';
4
+
5
+ export const listener = ({state, options}) => {
6
+ let {index} = state;
7
+ const {menu} = options;
8
+ const n = keys(menu).length - 1;
9
+
10
+ if (index < n)
11
+ ++index;
12
+
13
+ return {
14
+ index,
15
+ };
16
+ };
@@ -0,0 +1,16 @@
1
+ const {values} = Object;
2
+
3
+ export const key = 'Enter';
4
+
5
+ export const listener = ({options, state}) => {
6
+ const {index} = state;
7
+ const {menu} = options;
8
+
9
+ const fn = values(menu)[index];
10
+ setTimeout(fn);
11
+
12
+ return {
13
+ command: 'hide',
14
+ index: -1,
15
+ };
16
+ };
@@ -0,0 +1,6 @@
1
+ export const key = 'Escape';
2
+
3
+ export const listener = () => ({
4
+ command: 'hide',
5
+ index: -1,
6
+ });
@@ -0,0 +1,9 @@
1
+ export const key = 'F9';
2
+
3
+ export const listener = () => ({
4
+ command: 'show',
5
+ position: {
6
+ left: 0,
7
+ top: 0,
8
+ },
9
+ });
@@ -0,0 +1,21 @@
1
+ import * as contextMenu from './context-menu.js';
2
+ import * as click from './click.js';
3
+ import * as escape from './escape.js';
4
+ import * as down from './down.js';
5
+ import * as up from './up.js';
6
+ import * as f9 from './f9.js';
7
+ import * as enter from './enter.js';
8
+ import * as mouseEnter from './mouse-enter.js';
9
+ import * as itemClick from './item-click.js';
10
+
11
+ export const addons = [
12
+ contextMenu,
13
+ click,
14
+ escape,
15
+ down,
16
+ up,
17
+ f9,
18
+ enter,
19
+ mouseEnter,
20
+ itemClick,
21
+ ];
@@ -0,0 +1,16 @@
1
+ export const name = 'menu';
2
+ export const events = ['click'];
3
+
4
+ export const listener = ({event, options}) => {
5
+ const menuItemElement = document.elementFromPoint(event.clientX, event.clientY);
6
+ const name = menuItemElement.textContent.trim();
7
+ const {menu} = options;
8
+ const fn = menu[name];
9
+
10
+ setTimeout(fn);
11
+
12
+ return {
13
+ index: -1,
14
+ command: 'hide',
15
+ };
16
+ };
@@ -0,0 +1,5 @@
1
+ export const name = 'menu';
2
+ export const events = ['mouseenter'];
3
+ export const listener = () => ({
4
+ index: -1,
5
+ });
@@ -0,0 +1,12 @@
1
+ export const key = 'ArrowUp';
2
+
3
+ export const listener = ({state}) => {
4
+ let {index} = state;
5
+
6
+ if (index)
7
+ --index;
8
+
9
+ return {
10
+ index,
11
+ };
12
+ };
@@ -0,0 +1,22 @@
1
+ import {rules} from './rules/index.js';
2
+ import {hydrate} from '../aleman/index.js';
3
+ import {initState} from './state.js';
4
+ import {addons} from './addons/index.js';
5
+
6
+ const {assign} = Object;
7
+
8
+ export const hydrateMenu = (element, options, menu) => {
9
+ assign(options, {
10
+ menu,
11
+ });
12
+
13
+ const state = initState(options);
14
+
15
+ hydrate(element, {
16
+ options,
17
+ state,
18
+ addons,
19
+ rules,
20
+ stateName: 'aleman-state-menu',
21
+ });
22
+ };
@@ -0,0 +1,9 @@
1
+ {
2
+ "imports": {
3
+ "putout": "https://esm.sh/@putout/bundle",
4
+ "@putout/processor-html": "https://esm.sh/@putout/processor-html@14.1.1",
5
+ "html-escaper": "https://esm.sh/html-escaper",
6
+ "once": "https://esm.sh/once",
7
+ "fullstore": "https://esm.sh/fullstore"
8
+ }
9
+ }
package/menu/menu.js CHANGED
@@ -1,43 +1,60 @@
1
+ const {stringify} = JSON;
2
+
1
3
  export const createMenu = async (element, options, menuData) => {
2
- createHydrate();
3
- createMap();
4
+ const hydrateElement = createHydrate();
5
+
6
+ await createMap();
7
+ await createLink();
4
8
 
5
- createLink();
6
- const {hydrateMenu} = await import('./main.js');
9
+ createStateElement();
10
+ const {hydrateMenu} = await import('./hydrate-menu.js');
7
11
 
8
- hydrateMenu(element, options, menuData);
12
+ hydrateMenu(hydrateElement, options, menuData);
9
13
  };
10
14
 
11
- function createLink() {
12
- const style = document.createElement('link');
15
+ async function createLink() {
16
+ const style = document.createElement('style');
17
+ const content = await import('./menu.css', {
18
+ with: {
19
+ type: 'css',
20
+ },
21
+ });
22
+
23
+ for (const rule of content.default.cssRules) {
24
+ style.innerHTML += rule.cssText;
25
+ }
13
26
 
14
- style.rel = 'stylesheet';
15
- style.href = 'https://esm.sh/aleman@1.0.15/menu/menu.css';
16
27
  document.head.appendChild(style);
17
28
  }
18
29
 
19
30
  function createHydrate() {
20
31
  const section = document.createElement('section');
21
32
 
22
- section.dataset.name = 'hydrate';
23
- section.innerHTML = `<ul data-name="menu" class="menu menu-hidden" style="left: 0; top: 20px;">
24
- </ul>`;
33
+ section.dataset.name = 'aleman-hydrate-menu';
34
+ section.innerHTML = `<ul data-name="menu" class="menu menu-hidden"></ul>`;
35
+ document.body.append(section);
36
+
37
+ return section;
38
+ }
39
+
40
+ function createStateElement() {
41
+ const section = document.createElement('section');
42
+
43
+ section.classList.add('menu-hidden');
44
+ section.dataset.name = 'aleman-state-menu';
25
45
  document.body.append(section);
26
46
  }
27
47
 
28
- function createMap() {
48
+ async function createMap() {
49
+ const {default: importmap} = await import('./importmap.json', {
50
+ with: {
51
+ type: 'json',
52
+ },
53
+ });
54
+
29
55
  const script = document.createElement('script');
30
56
 
31
57
  script.type = 'importmap';
32
- script.innerHTML = `
33
- {
34
- "imports": {
35
- "putout": "https://esm.sh/@putout/bundle",
36
- "@putout/processor-html": "https://esm.sh/@putout/processor-html",
37
- "html-escaper": "https://esm.sh/html-escaper",
38
- "once": "https://esm.sh/once"
39
- }
40
- }
41
- `;
58
+ script.innerHTML = stringify(importmap, null, 4);
42
59
  document.body.append(script);
43
60
  }
@@ -1,19 +1,13 @@
1
1
  import * as setPosition from './set-position/index.js';
2
- import * as unselectAll from './unselect-all/index.js';
3
2
  import * as buildMenu from './build-menu/index.js';
4
- import * as select from './select/index.js';
5
- import * as unselect from './unselect/index.js';
6
3
  import * as menu from './menu/index.js';
7
- import * as removeButton from './remove-button/index.js';
8
- import * as setValue from './set-value/index.js';
4
+ import * as select from './select/index.js';
5
+ import * as unselectAll from './unselect-all/index.js';
9
6
 
10
7
  export const rules = {
11
- 'set-value': setValue,
12
- 'remove-button': removeButton,
13
8
  'menu': menu,
14
- 'select': select,
15
9
  'build-menu': buildMenu,
16
- 'unselect': unselect,
17
- 'unselect-all': unselectAll,
18
10
  'set-position': setPosition,
11
+ 'select': select,
12
+ 'select-all': unselectAll,
19
13
  };
@@ -1,5 +1,5 @@
1
1
  <ul data-name="menu" class="menu menu-hidden">
2
- <li data-name="menu-item" className="menu-item icon icon-view menu-item-selected">
2
+ <li data-name="menu-item" className='menu-item icon icon-view'>
3
3
  <label data-menu-path="View">View</label>
4
4
  </li>
5
5
  <li data-name="menu-item" className='menu-item icon icon-edit menu-item-selected'>
@@ -5,9 +5,12 @@ const {setLiteralValue} = operator;
5
5
 
6
6
  export const report = () => `Select item`;
7
7
 
8
- export const fix = (path) => {
8
+ export const fix = ({path, prev, next}) => {
9
9
  const {value} = path.node;
10
10
  setLiteralValue(value, `${value.value} menu-item-selected`);
11
+
12
+ unselect(prev);
13
+ unselect(next);
11
14
  };
12
15
 
13
16
  export const traverse = ({options, push}) => ({
@@ -28,19 +31,25 @@ export const traverse = ({options, push}) => ({
28
31
  .get('children')
29
32
  .filter(isJSXElement);
30
33
 
31
- const next = children[index];
34
+ const prev = children[index - 1];
35
+ const current = children[index];
36
+ const next = children[index + 1];
32
37
 
33
- if (!next)
38
+ if (!current)
34
39
  return;
35
40
 
36
- for (const attr of next.get('openingElement.attributes')) {
41
+ for (const attr of current.get('openingElement.attributes')) {
37
42
  const {name, value} = attr.node;
38
43
 
39
44
  if (name.name !== 'className')
40
45
  continue;
41
46
 
42
47
  if (!value.value.includes('menu-item-selected')) {
43
- push(attr);
48
+ push({
49
+ path: attr,
50
+ prev,
51
+ next,
52
+ });
44
53
  break;
45
54
  }
46
55
  }
@@ -59,3 +68,18 @@ function checkDataName(path) {
59
68
 
60
69
  return false;
61
70
  }
71
+
72
+ function unselect(path) {
73
+ if (!path)
74
+ return;
75
+
76
+ for (const attr of path.get('openingElement.attributes')) {
77
+ const {name, value} = attr.node;
78
+
79
+ if (name.name !== 'className')
80
+ continue;
81
+
82
+ if (value.value.includes('menu-item-selected'))
83
+ setLiteralValue(value, value.value.replace(' menu-item-selected', ''));
84
+ }
85
+ }
@@ -0,0 +1,2 @@
1
+ <ul data-name="menu" class="menu menu-hidden">
2
+ </ul>;
@@ -0,0 +1,2 @@
1
+ <ul data-name="menu" class="menu menu-hidden" style='left: 33px; top: 20px;'>
2
+ </ul>;