aleman 1.2.7 → 1.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/ChangeLog CHANGED
@@ -1,3 +1,10 @@
1
+ 2025.09.04, v1.3.0
2
+
3
+ feature:
4
+ - 42707d3 rules: unselect-all: add
5
+ - ed5c1a6 rules: submenu
6
+ - 7776881 menu: left: close submenu
7
+
1
8
  2025.09.04, v1.2.7
2
9
 
3
10
  feature:
@@ -8,5 +8,6 @@ export const listener = ({options, state}) => {
8
8
  return {
9
9
  command: 'hide',
10
10
  index: -1,
11
+ showSubmenu: false,
11
12
  };
12
13
  };
@@ -34,6 +34,7 @@ const listener = ({event, state, options}) => {
34
34
 
35
35
  return {
36
36
  command,
37
+ showSubmenu: false,
37
38
  position: {
38
39
  x,
39
40
  y: y - 14,
@@ -6,6 +6,8 @@ export const keys = [
6
6
  ];
7
7
  export const preventDefault = true;
8
8
 
9
+ export const filter = ({state}) => state.command === 'show';
10
+
9
11
  export const listener = ({state, options}) => {
10
12
  let {
11
13
  index,
@@ -15,20 +17,25 @@ export const listener = ({state, options}) => {
15
17
 
16
18
  const {menu} = options;
17
19
  const n = Object.keys(menu).length - 1;
20
+
21
+ if (!insideSubmenu && index < n)
22
+ ++index;
23
+
18
24
  const submenu = getSubmenu({
19
- state,
25
+ index,
20
26
  options,
21
27
  });
22
- const submenuCount = Object.keys(submenu).length - 1;
23
28
 
24
- if (!insideSubmenu && index < n)
25
- ++index;
29
+ const submenuCount = Object.keys(submenu).length - 1;
26
30
 
27
31
  if (insideSubmenu && submenuIndex < submenuCount)
28
32
  ++submenuIndex;
29
33
 
34
+ const showSubmenu = submenuCount > -1;
35
+
30
36
  return {
31
37
  index,
32
38
  submenuIndex,
39
+ showSubmenu,
33
40
  };
34
41
  };
@@ -4,6 +4,7 @@ export const listener = ({state, options}) => {
4
4
  options.beforeHide?.(state);
5
5
  return {
6
6
  command: 'hide',
7
+ showSubmenu: false,
7
8
  index: -1,
8
9
  };
9
10
  };
@@ -18,5 +18,6 @@ const listener = ({event, options}) => {
18
18
  return {
19
19
  index: -1,
20
20
  command: 'hide',
21
+ showSubmenu: false,
21
22
  };
22
23
  };
@@ -7,4 +7,5 @@ export const preventDefault = true;
7
7
  export const listener = () => ({
8
8
  submenuIndex: 0,
9
9
  insideSubmenu: false,
10
+ showSubmenu: false,
10
11
  });
@@ -7,14 +7,17 @@ export const keys = [
7
7
  export const preventDefault = true;
8
8
 
9
9
  export const filter = ({state, options}) => {
10
+ const {index} = state;
10
11
  const submenu = getSubmenu({
11
- state,
12
+ index,
12
13
  options,
13
14
  });
15
+
14
16
  return Object.keys(submenu).length;
15
17
  };
16
18
 
17
19
  export const listener = () => ({
18
20
  submenuIndex: 0,
19
21
  insideSubmenu: true,
22
+ showSubmenu: true,
20
23
  });
@@ -1,7 +1,6 @@
1
1
  const isObject = (a) => a && typeof a === 'object';
2
2
 
3
- export function getSubmenu({state, options}) {
4
- const {index} = state;
3
+ export function getSubmenu({index, options}) {
5
4
  const {menu} = options;
6
5
  const currentName = Object.keys(menu)[index];
7
6
  const submenu = menu[currentName];
package/menu/addons/up.js CHANGED
@@ -1,3 +1,5 @@
1
+ import {getSubmenu} from './submenu/index.js';
2
+
1
3
  export const keys = [
2
4
  'ArrowUp',
3
5
  'k',
@@ -13,6 +15,8 @@ export const listener = ({state, options}) => {
13
15
  submenuIndex,
14
16
  } = state;
15
17
 
18
+ const count = Object.keys(menu).length;
19
+
16
20
  if (insideSubmenu && submenuIndex > 0)
17
21
  --submenuIndex;
18
22
 
@@ -20,10 +24,20 @@ export const listener = ({state, options}) => {
20
24
  --index;
21
25
 
22
26
  if (index === -1)
23
- index = Object.keys(menu).length - 1;
27
+ index = count - 1;
28
+
29
+ const submenu = getSubmenu({
30
+ index,
31
+ options,
32
+ });
33
+
34
+ const submenuCount = Object.keys(submenu).length;
35
+
36
+ const showSubmenu = submenuCount > 0;
24
37
 
25
38
  return {
26
39
  index,
27
40
  submenuIndex,
41
+ showSubmenu,
28
42
  };
29
43
  };
package/menu/menu.css CHANGED
@@ -46,11 +46,7 @@
46
46
  display: none;
47
47
  }
48
48
 
49
- .menu-item:hover > .menu {
50
- display: block;
51
- }
52
-
53
- .menu-item-selected > .menu,.menu-item:hover > .menu {
49
+ .menu-submenu-show > .menu, .menu-item:hover > .menu {
54
50
  display: block;
55
51
  }
56
52
 
@@ -10,6 +10,6 @@ export const rules = {
10
10
  'build-menu': buildMenu,
11
11
  'set-position': setPosition,
12
12
  'select': select,
13
- 'select-all': unselectAll,
13
+ 'unselect-all': unselectAll,
14
14
  'submenu': submenu,
15
15
  };
@@ -6,17 +6,29 @@ const {setLiteralValue} = operator;
6
6
 
7
7
  export const report = () => `Select item`;
8
8
 
9
- export const fix = ({path, prev, next}) => {
9
+ export const fix = ({path, current, prev, next, showSubmenu}) => {
10
10
  const {value} = path.node;
11
- setLiteralValue(value, `${value.value} menu-item-selected`);
11
+
12
+ if (!value.value.includes('menu-item-selected'))
13
+ setLiteralValue(value, `${value.value} menu-item-selected`);
14
+
15
+ addShowSubmenu(current, {
16
+ showSubmenu,
17
+ });
12
18
 
13
19
  unselect(prev);
14
20
  unselect(next);
21
+ removeShowSubmenu(next);
22
+ removeShowSubmenu(prev);
15
23
  };
16
24
 
17
25
  export const traverse = ({options, push}) => ({
18
26
  JSXOpeningElement(path) {
19
- const {name = 'menu', index = 1} = options;
27
+ const {
28
+ name = 'menu',
29
+ index = 1,
30
+ showSubmenu,
31
+ } = options;
20
32
 
21
33
  if (path.node.name.name !== 'li')
22
34
  return;
@@ -42,19 +54,19 @@ export const traverse = ({options, push}) => ({
42
54
  return;
43
55
 
44
56
  for (const attr of current.get('openingElement.attributes')) {
45
- const {name, value} = attr.node;
57
+ const {name} = attr.node;
46
58
 
47
59
  if (name.name !== 'className')
48
60
  continue;
49
61
 
50
- if (!value.value.includes('menu-item-selected')) {
51
- push({
52
- path: attr,
53
- prev,
54
- next,
55
- });
56
- break;
57
- }
62
+ push({
63
+ path: attr,
64
+ current,
65
+ prev,
66
+ next,
67
+ showSubmenu,
68
+ });
69
+ break;
58
70
  }
59
71
  },
60
72
  });
@@ -73,3 +85,43 @@ function unselect(path) {
73
85
  setLiteralValue(value, value.value.replace(' menu-item-selected', ''));
74
86
  }
75
87
  }
88
+
89
+ function addShowSubmenu(path, {showSubmenu}) {
90
+ for (const attr of path.get('openingElement.attributes')) {
91
+ const {name, value} = attr.node;
92
+
93
+ if (name.name !== 'className')
94
+ continue;
95
+
96
+ const currentValue = value.value;
97
+
98
+ if (showSubmenu && !currentValue.includes('menu-submenu-show')) {
99
+ setLiteralValue(value, `${currentValue} menu-submenu-show`);
100
+ break;
101
+ }
102
+
103
+ if (!showSubmenu && currentValue.includes('menu-submenu-show')) {
104
+ setLiteralValue(value, currentValue.replace('menu-submenu-show', ''));
105
+ break;
106
+ }
107
+ }
108
+ }
109
+
110
+ function removeShowSubmenu(path) {
111
+ if (!path)
112
+ return;
113
+
114
+ for (const attr of path.get('openingElement.attributes')) {
115
+ const {name, value} = attr.node;
116
+
117
+ if (name.name !== 'className')
118
+ continue;
119
+
120
+ const currentValue = value.value;
121
+
122
+ if (currentValue.includes('menu-submenu-show')) {
123
+ setLiteralValue(value, currentValue.replace(' menu-submenu-show', ''));
124
+ break;
125
+ }
126
+ }
127
+ }
@@ -42,10 +42,10 @@
42
42
  <li data-menu-path="New" data-name="menu-item" className="menu-item icon icon-edit menu-item-selected">
43
43
  <label data-menu-path="New">New</label>
44
44
  <ul data-name="menu" class="menu menu-hidden">
45
- <li data-menu-path="New.File" data-name="menu-item" className="menu-item icon icon-view menu-item-selected">
45
+ <li data-menu-path="New.File" data-name="menu-item" className='menu-item icon icon-view'>
46
46
  <label data-menu-path="New.File">File</label>
47
47
  </li>
48
- <li data-menu-path="New.Directory" data-name="menu-item" className="menu-item icon icon-edit">
48
+ <li data-menu-path="New.Directory" data-name="menu-item" className='menu-item icon icon-edit'>
49
49
  <label data-menu-path="New.Directory">Directory</label>
50
50
  </li>
51
51
  </ul>
@@ -0,0 +1,17 @@
1
+ // first selected
2
+ <ul data-name="menu" class="menu menu-hidden">
3
+ <li data-menu-path="Upload" data-name="menu-item" className="menu-item icon icon-view menu-item-selected">
4
+ <label data-menu-path="Upload">Upload</label>
5
+ </li>
6
+ <li data-menu-path="New" data-name="menu-item" className="menu-item icon icon-edit">
7
+ <label data-menu-path="New">New</label>
8
+ <ul data-name="menu" class="menu menu-hidden">
9
+ <li data-menu-path="New.File" data-name="menu-item" className="menu-item icon icon-view">
10
+ <label data-menu-path="New.File">File</label>
11
+ </li>
12
+ <li data-menu-path="New.Directory" data-name="menu-item" className="menu-item icon icon-edit">
13
+ <label data-menu-path="New.Directory">Directory</label>
14
+ </li>
15
+ </ul>
16
+ </li>
17
+ </ul>;
@@ -1,9 +1,10 @@
1
1
  import {operator, types} from 'putout';
2
+ import {checkDataName} from '../check-data-name.js';
2
3
 
3
4
  const {isJSXElement} = types;
4
5
  const {setLiteralValue} = operator;
5
6
 
6
- export const report = () => `Select right`;
7
+ export const report = ({insideSubmenu}) => `${insideSubmenu ? 'Show' : 'Hide'} submenu`;
7
8
 
8
9
  export const fix = ({path, prev, next, insideSubmenu}) => {
9
10
  const {value} = path.node;
@@ -17,8 +18,10 @@ export const fix = ({path, prev, next, insideSubmenu}) => {
17
18
  return;
18
19
  }
19
20
 
20
- const newValue = `${value.value} menu-item-selected`;
21
- setLiteralValue(value, newValue);
21
+ if (!value.value.includes('menu-item-selected')) {
22
+ const newValue = `${value.value} menu-item-selected`;
23
+ setLiteralValue(value, newValue);
24
+ }
22
25
  };
23
26
 
24
27
  export const traverse = ({options, push}) => ({
@@ -38,7 +41,9 @@ export const traverse = ({options, push}) => ({
38
41
  if (!isJSXElement(path.parentPath.parentPath))
39
42
  return;
40
43
 
41
- if (!checkDataName(path.parentPath.parentPath))
44
+ const openingElementPath = path.parentPath.parentPath.get('openingElement');
45
+
46
+ if (!checkDataName(openingElementPath))
42
47
  return;
43
48
 
44
49
  const children = path.parentPath
@@ -53,35 +58,17 @@ export const traverse = ({options, push}) => ({
53
58
  if (!current)
54
59
  return;
55
60
 
56
- for (const attr of current.get('openingElement.attributes')) {
57
- const {name, value} = attr.node;
58
-
59
- if (name.name !== 'className')
60
- continue;
61
-
62
- push({
63
- path: attr,
64
- insideSubmenu,
65
- prev,
66
- next,
67
- });
68
- }
61
+ const [currentClassPath] = getClassPath(current);
62
+
63
+ push({
64
+ path: currentClassPath,
65
+ insideSubmenu,
66
+ prev,
67
+ next,
68
+ });
69
69
  },
70
70
  });
71
71
 
72
- function checkDataName(path) {
73
- const attributes = path.get('openingElement.attributes');
74
-
75
- for (const attr of attributes) {
76
- const {name, value} = attr.node;
77
-
78
- if (name.name === 'data-name')
79
- return value.value === 'menu';
80
- }
81
-
82
- return false;
83
- }
84
-
85
72
  function isParentSelected(path) {
86
73
  const attributes = path.get('openingElement.attributes');
87
74
 
@@ -109,3 +96,20 @@ function unselect(path) {
109
96
  setLiteralValue(value, value.value.replace(' menu-item-selected', ''));
110
97
  }
111
98
  }
99
+
100
+ function getClassPath(path) {
101
+ if (!path)
102
+ return [null, ''];
103
+
104
+ for (const attr of path.get('openingElement.attributes')) {
105
+ const {name, value} = attr.node;
106
+
107
+ if (name.name !== 'className')
108
+ continue;
109
+
110
+ return [
111
+ attr,
112
+ value.value,
113
+ ];
114
+ }
115
+ }
package/menu/state.js CHANGED
@@ -8,6 +8,7 @@ export const initState = ({menu, name = 'menu'}) => {
8
8
  command: 'hide',
9
9
  insideSubmenu: false,
10
10
  submenuIndex: 0,
11
+ showSubmenu: false,
11
12
  index: -1,
12
13
  count,
13
14
  position: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aleman",
3
- "version": "1.2.7",
3
+ "version": "1.3.0",
4
4
  "type": "module",
5
5
  "author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
6
6
  "description": "🐊Putout-based framework for web",