@neovici/cosmoz-autocomplete 9.0.2 → 10.0.1
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/README.md +4 -4
- package/dist/autocomplete/autocomplete.d.ts +2 -0
- package/dist/autocomplete/autocomplete.js +21 -6
- package/dist/autocomplete/util.js +14 -2
- package/dist/listbox/index.d.ts +7 -2
- package/dist/listbox/index.js +8 -16
- package/dist/listbox/use-listbox.d.ts +1 -5
- package/dist/listbox/use-listbox.js +1 -10
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
cosmoz-autocomplete
|
|
2
|
-
==================
|
|
1
|
+
# cosmoz-autocomplete
|
|
3
2
|
|
|
4
3
|
[](https://github.com/Neovici/cosmoz-autocomplete/actions?workflow=Github+CI)
|
|
5
4
|
[](https://depfu.com/github/Neovici/cosmoz-autocomplete?project_id=9639)
|
|
@@ -16,13 +15,14 @@ cosmoz-autocomplete
|
|
|
16
15
|
### Installing
|
|
17
16
|
|
|
18
17
|
Using npm:
|
|
18
|
+
|
|
19
19
|
```bash
|
|
20
20
|
npm install --save @neovici/cosmoz-autocomplete
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
### Usage
|
|
24
24
|
|
|
25
|
-
```
|
|
25
|
+
```javascript
|
|
26
26
|
import { html } from 'lit-html';
|
|
27
|
-
html`<cosmoz-autocomplete .source=${[
|
|
27
|
+
html`<cosmoz-autocomplete .source=${['A', 'B', 'C', 'D']} />`;
|
|
28
28
|
```
|
|
@@ -2,6 +2,7 @@ import '@neovici/cosmoz-input';
|
|
|
2
2
|
import './skeleton-span';
|
|
3
3
|
import style from './styles.css';
|
|
4
4
|
import { Props as Base, RProps } from './use-autocomplete';
|
|
5
|
+
import { Placement } from '@neovici/cosmoz-dropdown/use-floating';
|
|
5
6
|
export interface Props<I> extends Base<I> {
|
|
6
7
|
invalid?: boolean;
|
|
7
8
|
errorMessage?: string;
|
|
@@ -14,6 +15,7 @@ export interface Props<I> extends Base<I> {
|
|
|
14
15
|
itemLimit?: number;
|
|
15
16
|
wrap?: boolean;
|
|
16
17
|
defaultIndex?: number;
|
|
18
|
+
placement?: Placement;
|
|
17
19
|
}
|
|
18
20
|
type AProps<I> = Omit<Props<I>, keyof RProps<I>> & RProps<I> & {
|
|
19
21
|
onInputRef?: (el?: Element) => void;
|
|
@@ -2,7 +2,6 @@ import '@neovici/cosmoz-input';
|
|
|
2
2
|
import './skeleton-span';
|
|
3
3
|
import { useHost } from '@neovici/cosmoz-utils/hooks/use-host';
|
|
4
4
|
import { useImperativeApi } from '@neovici/cosmoz-utils/hooks/use-imperative-api';
|
|
5
|
-
import { useCallback } from '@pionjs/pion';
|
|
6
5
|
import { html, nothing } from 'lit-html'; // eslint-disable-line object-curly-newline
|
|
7
6
|
import { live } from 'lit-html/directives/live.js';
|
|
8
7
|
import { until } from 'lit-html/directives/until.js';
|
|
@@ -12,21 +11,36 @@ import { selection } from './selection';
|
|
|
12
11
|
import style from './styles.css';
|
|
13
12
|
import { useAutocomplete } from './use-autocomplete';
|
|
14
13
|
import { useOverflow } from './use-overflow';
|
|
14
|
+
import { ref } from 'lit-html/directives/ref.js';
|
|
15
|
+
import { useFloating, defaultMiddleware, size, } from '@neovici/cosmoz-dropdown/use-floating';
|
|
15
16
|
const inputParts = ['input', 'control', 'label', 'line', 'error', 'wrap']
|
|
16
17
|
.map((part) => `${part}: input-${part}`)
|
|
17
18
|
.join();
|
|
18
19
|
const blank = () => nothing;
|
|
20
|
+
const middleware = [
|
|
21
|
+
size({
|
|
22
|
+
apply({ rects, elements }) {
|
|
23
|
+
Object.assign(elements.floating.style, {
|
|
24
|
+
minWidth: `${Math.max(rects.reference.width, rects.floating.width)}px`,
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
}),
|
|
28
|
+
...defaultMiddleware,
|
|
29
|
+
];
|
|
19
30
|
const autocomplete = (props) => {
|
|
20
|
-
const { active, invalid, errorMessage, label, placeholder, disabled, noLabelFloat, alwaysFloatLabel, textual, text, onText, onFocus, onClick, onDeselect, value, limit, min, showSingle, items, source$, } = props, host = useHost(), isOne = limit == 1, // eslint-disable-line eqeqeq
|
|
21
|
-
isSingle = isOne && value?.[0] != null
|
|
22
|
-
|
|
23
|
-
|
|
31
|
+
const { active, invalid, errorMessage, label, placeholder, disabled, noLabelFloat, alwaysFloatLabel, textual, text, onText, onFocus, onClick, onDeselect, value, limit, min, showSingle, items, source$, placement, } = props, host = useHost(), isOne = limit == 1, // eslint-disable-line eqeqeq
|
|
32
|
+
isSingle = isOne && value?.[0] != null;
|
|
33
|
+
const { styles, setReference, setFloating } = useFloating({
|
|
34
|
+
placement,
|
|
35
|
+
middleware,
|
|
36
|
+
});
|
|
24
37
|
useImperativeApi({
|
|
25
38
|
focus: () => host.shadowRoot?.querySelector('#input')?.focus(),
|
|
26
39
|
}, []);
|
|
27
40
|
return html `<cosmoz-input
|
|
28
41
|
id="input"
|
|
29
42
|
part="input"
|
|
43
|
+
${ref(setReference)}
|
|
30
44
|
.label=${label}
|
|
31
45
|
.placeholder=${isSingle ? undefined : placeholder}
|
|
32
46
|
?no-label-float=${noLabelFloat}
|
|
@@ -59,9 +73,10 @@ const autocomplete = (props) => {
|
|
|
59
73
|
|
|
60
74
|
${when(active && !(isSingle && !showSingle), () => listbox({
|
|
61
75
|
...props,
|
|
62
|
-
anchor,
|
|
63
76
|
items,
|
|
64
77
|
multi: !isOne,
|
|
78
|
+
setFloating,
|
|
79
|
+
styles,
|
|
65
80
|
}, when(items.length < 5, () => until(source$.then(blank, blank), html `<cosmoz-autocomplete-skeleton-span></cosmoz-autocomplete-skeleton-span>`))))}`;
|
|
66
81
|
}, Autocomplete = (props) => {
|
|
67
82
|
const thru = {
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
import { useCallback } from '@pionjs/pion';
|
|
2
|
+
/**
|
|
3
|
+
* @see https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript
|
|
4
|
+
* @see https://medium.com/nerd-for-tech/basics-of-javascript-string-normalize-method-f3241174c2d0
|
|
5
|
+
* @see https://www.codu.co/articles/remove-accents-from-a-javascript-string-skgp1inb
|
|
6
|
+
*
|
|
7
|
+
* @param {string} str string from which to remove accents
|
|
8
|
+
* @returns {string} string w/o accents
|
|
9
|
+
*/
|
|
10
|
+
const removeAccents = (str) => {
|
|
11
|
+
return str.normalize('NFD').replace(/[\u0300-\u036f]/gu, '');
|
|
12
|
+
};
|
|
2
13
|
export const search = (source, query, textual) => {
|
|
3
14
|
if (!query)
|
|
4
15
|
return source;
|
|
5
|
-
const
|
|
16
|
+
const normalizedQuery = removeAccents(query.toLowerCase());
|
|
6
17
|
const matches = [];
|
|
7
18
|
for (const item of source) {
|
|
8
|
-
const
|
|
19
|
+
const normalizedText = removeAccents(textual(item).toLowerCase());
|
|
20
|
+
const index = normalizedText.indexOf(normalizedQuery);
|
|
9
21
|
if (index < 0) {
|
|
10
22
|
continue;
|
|
11
23
|
}
|
package/dist/listbox/index.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { Props } from './use-listbox';
|
|
2
|
-
|
|
2
|
+
import { StyleInfo } from 'lit-html/directives/style-map.js';
|
|
3
|
+
interface ListboxProps<I> extends Props<I> {
|
|
3
4
|
multi?: boolean;
|
|
4
|
-
|
|
5
|
+
setFloating: (el?: Element) => void;
|
|
6
|
+
styles: StyleInfo;
|
|
7
|
+
}
|
|
8
|
+
export declare const listbox: <I>({ multi, setFloating, styles, ...thru }: ListboxProps<I>, content: unknown) => import("lit-html").TemplateResult<1>;
|
|
9
|
+
export {};
|
package/dist/listbox/index.js
CHANGED
|
@@ -7,6 +7,8 @@ import { component, html, useEffect, useMemo, useRef } from '@pionjs/pion';
|
|
|
7
7
|
import { ref } from 'lit-html/directives/ref.js';
|
|
8
8
|
import style, { styles } from './style.css';
|
|
9
9
|
import { properties, useListbox } from './use-listbox';
|
|
10
|
+
import { connectable } from '@neovici/cosmoz-dropdown/connectable';
|
|
11
|
+
import { styleMap } from 'lit-html/directives/style-map.js';
|
|
10
12
|
const Listbox = (props) => {
|
|
11
13
|
const listRef = useRef(undefined);
|
|
12
14
|
const { position, items, renderItem, height, itemHeight } = useListbox(props);
|
|
@@ -24,8 +26,8 @@ const Listbox = (props) => {
|
|
|
24
26
|
}), [itemHeight]);
|
|
25
27
|
return html `<div
|
|
26
28
|
class="items"
|
|
27
|
-
${ref((el) => (listRef.current = el))}
|
|
28
29
|
style="min-height: ${height}px"
|
|
30
|
+
${ref((el) => (listRef.current = el))}
|
|
29
31
|
>
|
|
30
32
|
<div virtualizer-sizer></div>
|
|
31
33
|
${virtualize({
|
|
@@ -37,24 +39,14 @@ const Listbox = (props) => {
|
|
|
37
39
|
</div>
|
|
38
40
|
<slot></slot>`;
|
|
39
41
|
};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
const showPopover = (popover) => {
|
|
45
|
-
const popoverElement = popover;
|
|
46
|
-
if (supportsPopover()) {
|
|
47
|
-
requestAnimationFrame(() => {
|
|
48
|
-
popoverElement?.showPopover();
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
customElements.define('cosmoz-listbox', component(Listbox, { styleSheets: [sheet(style)] }));
|
|
53
|
-
export const listbox = ({ multi, ...thru }, content) => html `<cosmoz-listbox
|
|
54
|
-
${ref(showPopover)}
|
|
42
|
+
customElements.define('cosmoz-listbox', connectable(component(Listbox, { styleSheets: [sheet(style)] })));
|
|
43
|
+
export const listbox = ({ multi, setFloating, styles, ...thru }, content) => html `<cosmoz-listbox
|
|
44
|
+
style="${styleMap(styles)}"
|
|
45
|
+
@connected="${(e) => e.target.showPopover?.()}"
|
|
55
46
|
popover="manual"
|
|
56
47
|
part="listbox"
|
|
57
48
|
?multi=${multi}
|
|
49
|
+
${ref(setFloating)}
|
|
58
50
|
...=${spreadProps(props(properties)(thru))}
|
|
59
51
|
>${content}</cosmoz-listbox
|
|
60
52
|
>`;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Placement } from '@neovici/cosmoz-dropdown/use-position';
|
|
2
1
|
import { useRenderItem, ItemRenderer } from './use-render-item';
|
|
3
2
|
export declare const properties: string[];
|
|
4
3
|
export interface Props<I> {
|
|
@@ -12,11 +11,8 @@ export interface Props<I> {
|
|
|
12
11
|
itemRenderer?: ItemRenderer<I>;
|
|
13
12
|
itemHeight?: number;
|
|
14
13
|
itemLimit?: number;
|
|
15
|
-
anchor?: () => HTMLElement | null;
|
|
16
|
-
confinement?: HTMLElement;
|
|
17
|
-
placement?: Placement;
|
|
18
14
|
}
|
|
19
|
-
export declare const useListbox: <I>({ value, valueProperty, items: _items, onSelect, defaultIndex, query, textual, itemRenderer, itemHeight, itemLimit,
|
|
15
|
+
export declare const useListbox: <I>({ value, valueProperty, items: _items, onSelect, defaultIndex, query, textual, itemRenderer, itemHeight, itemLimit, }: Props<I>) => {
|
|
20
16
|
position: import("./use-items").Position;
|
|
21
17
|
items: I[];
|
|
22
18
|
height: number;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { useMemo } from '@pionjs/pion';
|
|
2
|
-
import { useHost } from '@neovici/cosmoz-utils/hooks/use-host';
|
|
3
|
-
import { usePosition } from '@neovici/cosmoz-dropdown/use-position';
|
|
4
2
|
import { byValue } from './util';
|
|
5
3
|
import { useItems } from './use-items';
|
|
6
4
|
import { useRenderItem } from './use-render-item';
|
|
@@ -10,8 +8,6 @@ export const properties = [
|
|
|
10
8
|
'onSelect',
|
|
11
9
|
'textual',
|
|
12
10
|
'anchor',
|
|
13
|
-
'confinement',
|
|
14
|
-
'placement',
|
|
15
11
|
'itemHeight',
|
|
16
12
|
'itemLimit',
|
|
17
13
|
'itemRenderer',
|
|
@@ -20,7 +16,7 @@ export const properties = [
|
|
|
20
16
|
'valueProperty',
|
|
21
17
|
'loading',
|
|
22
18
|
];
|
|
23
|
-
export const useListbox = ({ value, valueProperty, items: _items, onSelect, defaultIndex, query, textual, itemRenderer, itemHeight = 40, itemLimit = 5,
|
|
19
|
+
export const useListbox = ({ value, valueProperty, items: _items, onSelect, defaultIndex, query, textual, itemRenderer, itemHeight = 40, itemLimit = 5, }) => {
|
|
24
20
|
const isSelected = useMemo(() => byValue(value, valueProperty), [value, valueProperty]),
|
|
25
21
|
// TODO: investigate if we can drop this
|
|
26
22
|
items = useMemo(() => _items.slice(), [_items, isSelected]), { position, highlight, select } = useItems({
|
|
@@ -30,11 +26,6 @@ export const useListbox = ({ value, valueProperty, items: _items, onSelect, defa
|
|
|
30
26
|
? undefined
|
|
31
27
|
: Number(defaultIndex),
|
|
32
28
|
});
|
|
33
|
-
usePosition({
|
|
34
|
-
host: useHost(),
|
|
35
|
-
...thru,
|
|
36
|
-
limit: true,
|
|
37
|
-
});
|
|
38
29
|
return {
|
|
39
30
|
position,
|
|
40
31
|
items,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neovici/cosmoz-autocomplete",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "10.0.1",
|
|
4
4
|
"description": "A autocomplete input web component",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lit-html",
|
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
"test:watch": "wtr --watch",
|
|
29
29
|
"e2e": "playwright test",
|
|
30
30
|
"prepare": "husky",
|
|
31
|
+
"prettier": "prettier --write \"**/*.{js,ts,json,css,md}\"",
|
|
32
|
+
"prettier:check": "prettier --check \"**/*.{js,ts,json,css,md}\"",
|
|
31
33
|
"storybook:start": "storybook dev -p 8000",
|
|
32
34
|
"storybook:build": "storybook build",
|
|
33
35
|
"storybook:deploy": "storybook-to-ghpages",
|
|
@@ -71,7 +73,7 @@
|
|
|
71
73
|
},
|
|
72
74
|
"dependencies": {
|
|
73
75
|
"@lit-labs/virtualizer": "^2.0.0",
|
|
74
|
-
"@neovici/cosmoz-dropdown": "^
|
|
76
|
+
"@neovici/cosmoz-dropdown": "^5.0.0",
|
|
75
77
|
"@neovici/cosmoz-input": "^5.0.2",
|
|
76
78
|
"@neovici/cosmoz-utils": "^6.0.0",
|
|
77
79
|
"@pionjs/pion": "^2.7.1",
|
|
@@ -91,16 +93,16 @@
|
|
|
91
93
|
"@storybook/storybook-deployer": "^2.8.5",
|
|
92
94
|
"@storybook/web-components": "7.6.17",
|
|
93
95
|
"@types/mocha": "^10.0.6",
|
|
94
|
-
"@types/node": "^
|
|
96
|
+
"@types/node": "^22.10.2",
|
|
95
97
|
"@web/storybook-builder": "^0.1.9",
|
|
96
98
|
"@web/storybook-framework-web-components": "^0.1.1",
|
|
97
|
-
"esbuild": "^0.
|
|
99
|
+
"esbuild": "^0.24.0",
|
|
98
100
|
"http-server": "^14.1.1",
|
|
99
101
|
"husky": "^9.0.0",
|
|
100
102
|
"rollup-plugin-esbuild": "^6.1.1",
|
|
101
103
|
"rollup-plugin-terser": "^7.0.2",
|
|
102
104
|
"semantic-release": "^24.0.0",
|
|
103
|
-
"sinon": "^
|
|
105
|
+
"sinon": "^19.0.0",
|
|
104
106
|
"storybook": "^7.6.17"
|
|
105
107
|
},
|
|
106
108
|
"overrides": {
|