@neovici/cosmoz-autocomplete 2.15.1 → 2.17.2

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/cosmoz-listbox.js CHANGED
@@ -63,6 +63,7 @@ const Listbox = host => {
63
63
  overflow: hidden;
64
64
  max-width: inherit;
65
65
  }
66
+ .items > :first-child { line-height: 1;}
66
67
  </style>
67
68
  <div class="items">${ scroll({ items, renderItem }) }</div>`;
68
69
  };
@@ -150,7 +150,7 @@ const
150
150
  .errorMessage=${ until(values$.then(() => errorMessage, e => e.message), errorMessage) }
151
151
  .value=${ live(text) }
152
152
  @value-changed=${ onText }
153
- @focused-changed=${ onFocus }
153
+ @focusin=${ onFocus } @focusout=${ onFocus }
154
154
  @click=${ onClick }
155
155
  autocomplete="off"
156
156
  exportparts=${ inputParts }
package/lib/use-focus.js CHANGED
@@ -1,10 +1,21 @@
1
1
  import { useEffect, useState, useCallback } from 'haunted';
2
2
  import { useMeta } from '@neovici/cosmoz-utils/lib/hooks/use-meta';
3
3
 
4
+ const isFocused = t => t.matches(':focus-within'),
5
+ blurEvs = ['focusout', 'blur'],
6
+ isBlurEvent = type => blurEvs.includes(type);
7
+
4
8
  export const useFocus = ({ disabled, onFocus }) => {
5
- const [{ focused, closed }, setFocus] = useState({ focused: false, closed: false }),
9
+ const [{ focused, closed } = {}, setState] = useState(),
6
10
  active = focused && !disabled,
7
- meta = useMeta({ closed });
11
+ meta = useMeta({ closed, onFocus }),
12
+ setClosed = useCallback(closed => setState(p => ({ ...p, closed })), []),
13
+ onToggle = useCallback(e => {
14
+ const target = e.currentTarget;
15
+ return isFocused(target)
16
+ ? setState(p => ({ focused: true, closed: !p?.closed }))
17
+ : target.focus();
18
+ }, []);
8
19
 
9
20
  useEffect(() => {
10
21
  if (!active) {
@@ -17,10 +28,10 @@ export const useFocus = ({ disabled, onFocus }) => {
17
28
  const { closed } = meta;
18
29
  if (e.key === 'Escape' && !closed) {
19
30
  e.preventDefault();
20
- setFocus(p => ({ ...p, closed: true }));
31
+ setClosed(true);
21
32
  } else if (['ArrowUp', 'Up'].includes(e.key) && closed) {
22
33
  e.preventDefault();
23
- setFocus(p => ({ ...p, closed: false }));
34
+ setClosed(false);
24
35
  }
25
36
  };
26
37
  document.addEventListener('keydown', handler, true);
@@ -29,11 +40,14 @@ export const useFocus = ({ disabled, onFocus }) => {
29
40
 
30
41
  return {
31
42
  active: active && !closed,
32
- setClosed: useCallback(closed => setFocus(p => ({ ...p, closed })), []),
43
+ setClosed,
44
+ onToggle,
33
45
  onFocus: useCallback(e => {
34
- const focused = e.target.focused;
35
- setFocus({ focused, closed: false });
36
- onFocus?.(focused);
37
- }, [onFocus])
46
+ const target = e.currentTarget,
47
+ focused = isFocused(target) || isBlurEvent(e.type)
48
+ && e.relatedTarget?.closest('[data-dropdown]');
49
+ setState({ focused });
50
+ meta.onFocus?.(focused);
51
+ }, [meta])
38
52
  };
39
53
  };
@@ -1,27 +1,11 @@
1
1
  import { useCallback, useEffect, useState, useMemo } from 'haunted';
2
- import getPosition from 'position.js';
2
+ import { useMeta } from '@neovici/cosmoz-utils/lib/hooks/use-meta';
3
3
  import { useKeyboard } from './use-keyboard';
4
- import { onScrolled } from './on-scrolled';
5
4
  import defaultItemRenderer from './item-renderer';
6
- import { useMeta } from '@neovici/cosmoz-utils/lib/hooks/use-meta';
7
5
  import { byValue } from './utils';
6
+ import { usePosition } from './use-position';
8
7
 
9
- const defaultPlacement = ['bottom-left', 'bottom-right', 'bottom', 'top-left', 'top-right', 'top'],
10
- position = (host, anchor, placement = defaultPlacement, confinement) => {
11
- const anchorBounds = anchor.getBoundingClientRect(),
12
- hostBounds = host.getBoundingClientRect(),
13
- { popupOffset: offset } = getPosition(hostBounds, anchorBounds, placement, {
14
- fixed: true,
15
- adjustXY: 'both',
16
- offsetParent: confinement
17
- }),
18
- { style } = host;
19
- style.left = offset.left + 'px';
20
- style.top = offset.top + 'px';
21
- style.minWidth = Math.max(anchorBounds.width, hostBounds.width) + 'px';
22
- },
23
-
24
- useItems = ({
8
+ const useItems = ({
25
9
  items,
26
10
  onSelect,
27
11
  defaultIndex = 0
@@ -55,35 +39,6 @@ const defaultPlacement = ['bottom-left', 'bottom-right', 'bottom', 'top-left', '
55
39
  return useCallback((item, i) => itemRenderer(item, i, info), [info, itemRenderer]);
56
40
  },
57
41
 
58
- usePosition = ({ anchor: anchorage, host, confinement, placement }) => {
59
- useEffect(() => {
60
- const anchor = typeof anchorage === 'function' ? anchorage() : anchorage;
61
- if (anchor == null) {
62
- return;
63
- }
64
- let rid;
65
- const reposition = () => position(host, anchor, placement, confinement),
66
- ro = new ResizeObserver(reposition);
67
-
68
- ro.observe(host);
69
- ro.observe(anchor);
70
-
71
- const onReposition = () => {
72
- cancelAnimationFrame(rid);
73
- rid = requestAnimationFrame(reposition);
74
- },
75
- offScroll = onScrolled(anchor, onReposition);
76
- window.addEventListener('resize', onReposition, true);
77
-
78
- return () => {
79
- ro.unobserve(host);
80
- ro.unobserve(anchor);
81
- offScroll();
82
- window.removeEventListener('resize', onReposition, true);
83
- cancelAnimationFrame(rid);
84
- };
85
- }, [anchorage, confinement, placement]);
86
- },
87
42
 
88
43
  useListbox = host => {
89
44
  const {
@@ -0,0 +1,49 @@
1
+ import { useEffect } from 'haunted';
2
+ import getPosition from 'position.js';
3
+ import { onScrolled } from './on-scrolled';
4
+
5
+ const defaultPlacement = ['bottom-left', 'bottom-right', 'bottom', 'top-left', 'top-right', 'top'],
6
+ position = (host, anchor, placement = defaultPlacement, confinement) => {
7
+ const anchorBounds = anchor.getBoundingClientRect(),
8
+ hostBounds = host.getBoundingClientRect(),
9
+ { popupOffset: offset } = getPosition(hostBounds, anchorBounds, placement, {
10
+ fixed: true,
11
+ adjustXY: 'both',
12
+ offsetParent: confinement
13
+ }),
14
+ { style } = host;
15
+ style.left = offset.left + 'px';
16
+ style.top = offset.top + 'px';
17
+ style.minWidth = Math.max(anchorBounds.width, hostBounds.width) + 'px';
18
+ },
19
+ usePosition = ({ anchor: anchorage, host, confinement, placement }) => {
20
+ useEffect(() => {
21
+ const anchor = typeof anchorage === 'function' ? anchorage() : anchorage;
22
+ if (anchor == null) {
23
+ return;
24
+ }
25
+ let rid;
26
+ const reposition = () => position(host, anchor, placement, confinement),
27
+ ro = new ResizeObserver(reposition);
28
+
29
+ ro.observe(host);
30
+ ro.observe(anchor);
31
+
32
+ const onReposition = () => {
33
+ cancelAnimationFrame(rid);
34
+ rid = requestAnimationFrame(reposition);
35
+ },
36
+ offScroll = onScrolled(anchor, onReposition);
37
+ window.addEventListener('resize', onReposition, true);
38
+
39
+ return () => {
40
+ ro.unobserve(host);
41
+ ro.unobserve(anchor);
42
+ offScroll();
43
+ window.removeEventListener('resize', onReposition, true);
44
+ cancelAnimationFrame(rid);
45
+ };
46
+ }, [anchorage, confinement, placement]);
47
+ };
48
+
49
+ export { usePosition };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neovici/cosmoz-autocomplete",
3
- "version": "2.15.1",
3
+ "version": "2.17.2",
4
4
  "description": "A autocomplete input web component",
5
5
  "keywords": [
6
6
  "lit-html",
@@ -56,7 +56,7 @@
56
56
  ]
57
57
  },
58
58
  "dependencies": {
59
- "@neovici/cosmoz-input": "^1.4.0",
59
+ "@neovici/cosmoz-input": "^1.5.0",
60
60
  "@neovici/cosmoz-utils": "^3.20.0",
61
61
  "@open-wc/lit-helpers": "^0.3.12",
62
62
  "haunted": "^4.7.0",
@@ -65,21 +65,19 @@
65
65
  "position.js": "^0.3.0"
66
66
  },
67
67
  "devDependencies": {
68
- "@commitlint/cli": "^12.0.0",
69
- "@commitlint/config-conventional": "^12.0.0",
70
- "@neovici/eslint-config": "^1.2.0",
68
+ "@commitlint/cli": "^15.0.0",
69
+ "@commitlint/config-conventional": "^15.0.0",
70
+ "@neovici/eslint-config": "^1.3.0",
71
71
  "@open-wc/demoing-storybook": "^2.1.0",
72
72
  "@open-wc/testing": "^2.5.32",
73
- "@semantic-release/changelog": "^5.0.1",
74
- "@semantic-release/git": "^9.0.0",
73
+ "@semantic-release/changelog": "^6.0.0",
74
+ "@semantic-release/git": "^10.0.0",
75
75
  "@storybook/storybook-deployer": "^2.8.5",
76
76
  "@web/test-runner": "^0.13.0",
77
77
  "@web/test-runner-selenium": "^0.5.0",
78
- "@webcomponents/webcomponentsjs": "^2.4.0",
79
- "eslint": "^7.0.0",
80
- "husky": "^6.0.0",
81
- "semantic-release": "^17.4.0",
82
- "sinon": "^11.0.0",
83
- "typescript": "^4.0.0"
78
+ "husky": "^7.0.0",
79
+ "semantic-release": "^18.0.0",
80
+ "sinon": "^12.0.0",
81
+ "typescript": "^4.5.0"
84
82
  }
85
83
  }