@neovici/cosmoz-input 3.2.0 → 3.4.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.
@@ -1,8 +1,9 @@
1
- import { html } from 'lit-html'; // eslint-disable-line object-curly-newline
1
+ import { html } from 'lit-html';
2
2
  import { live } from 'lit-html/directives/live.js';
3
3
  import { ifDefined } from 'lit-html/directives/if-defined.js';
4
4
  import { component } from 'haunted';
5
- import { useInput, useAllowedPattern } from './use-input';
5
+ import { useInput } from './use-input';
6
+ import { useAllowedPattern } from './use-allowed-pattern';
6
7
  import { render, attributes } from './render';
7
8
  const observedAttributes = [
8
9
  'type',
@@ -11,30 +12,35 @@ const observedAttributes = [
11
12
  'min',
12
13
  'max',
13
14
  'step',
15
+ 'autosize',
14
16
  ...attributes,
15
17
  ];
16
18
  export const Input = (host) => {
17
- const { type = 'text', pattern, allowedPattern, autocomplete, value, placeholder, readonly, disabled, min, max, step, maxlength, } = host, { onChange, onFocus, onInput } = useInput(host), onBeforeInput = useAllowedPattern(allowedPattern);
18
- return render(html `<input
19
- id="input"
20
- part="input"
21
- type=${type}
22
- pattern=${ifDefined(pattern)}
23
- autocomplete=${ifDefined(autocomplete)}
24
- placeholder=${placeholder || ' '}
25
- ?readonly=${readonly}
26
- ?aria-disabled=${disabled}
27
- ?disabled=${disabled}
28
- .value=${live(value ?? '')}
29
- maxlength=${ifDefined(maxlength)}
30
- @beforeinput=${onBeforeInput}
31
- @input=${onInput}
32
- @change=${onChange}
33
- @focus=${onFocus}
34
- @blur=${onFocus}
35
- min=${ifDefined(min)}
36
- max=${ifDefined(max)}
37
- step=${ifDefined(step)}
38
- />`, host);
19
+ const { type = 'text', pattern, allowedPattern, autocomplete, value, placeholder, readonly, disabled, min, max, step, maxlength, } = host, { onChange, onFocus, onInput } = useInput(host);
20
+ const onBeforeInput = useAllowedPattern(allowedPattern);
21
+ return render(html `
22
+ <input
23
+ style="--chars: ${value?.toString()?.length ?? 0}ch"
24
+ id="input"
25
+ part="input"
26
+ type=${type}
27
+ pattern=${ifDefined(pattern)}
28
+ autocomplete=${ifDefined(autocomplete)}
29
+ placeholder=${placeholder || ' '}
30
+ ?readonly=${readonly}
31
+ ?aria-disabled=${disabled}
32
+ ?disabled=${disabled}
33
+ .value=${live(value ?? '')}
34
+ maxlength=${ifDefined(maxlength)}
35
+ @beforeinput=${onBeforeInput}
36
+ @input=${onInput}
37
+ @change=${onChange}
38
+ @focus=${onFocus}
39
+ @blur=${onFocus}
40
+ min=${ifDefined(min)}
41
+ max=${ifDefined(max)}
42
+ step=${ifDefined(step)}
43
+ />
44
+ `, host);
39
45
  };
40
46
  customElements.define('cosmoz-input', component(Input, { observedAttributes }));
@@ -2,12 +2,13 @@ import { html } from 'lit-html'; // eslint-disable-line object-curly-newline
2
2
  import { live } from 'lit-html/directives/live.js';
3
3
  import { ifDefined } from 'lit-html/directives/if-defined.js';
4
4
  import { component } from 'haunted';
5
- import { useInput, useAutosize } from './use-input';
5
+ import { useInput } from './use-input';
6
+ import { useAutoHeight } from './use-auto-height';
6
7
  import { render, attributes } from './render';
7
8
  const observedAttributes = ['rows', ...attributes];
8
9
  export const Textarea = (host) => {
9
10
  const { autocomplete, value, placeholder, readonly, disabled, rows, cols, maxlength, } = host, { onChange, onFocus, onInput } = useInput(host);
10
- useAutosize(host);
11
+ useAutoHeight(host);
11
12
  return render(html `
12
13
  <textarea id="input" part="input" style="resize: none"
13
14
  autocomplete=${ifDefined(autocomplete)}
package/dist/render.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export declare type ObjectFromList<T extends ReadonlyArray<string>, V = string> = {
2
- [K in (T extends ReadonlyArray<infer U> ? U : never)]: V;
2
+ [K in T extends ReadonlyArray<infer U> ? U : never]: V;
3
3
  };
4
4
  export interface Render {
5
5
  label?: string;
package/dist/styles.js CHANGED
@@ -157,4 +157,30 @@ export const styles = css `
157
157
  #input::-webkit-inner-spin-button {
158
158
  z-index: 1;
159
159
  }
160
+
161
+ :host([no-spinner]) #input::-webkit-inner-spin-button {
162
+ display: none;
163
+ }
164
+ :host([no-spinner]) #input {
165
+ -moz-appearence: textfield;
166
+ }
167
+
168
+ :host([autosize]) {
169
+ width: max-content;
170
+ }
171
+ :host([autosize]) #input {
172
+ min-width: 2ch;
173
+ width: var(--chars);
174
+ }
175
+ :host([autosize][type='number']) #input {
176
+ --width: calc(var(--chars) + 0.25em);
177
+ }
178
+ :host([autosize][type='number']:not([no-spinner])) #input {
179
+ width: calc(var(--width) + 15px);
180
+ min-width: calc(2ch + 0.25em + 15px);
181
+ }
182
+ :host([autosize][type='number'][no-spinner]) #input {
183
+ width: var(--width);
184
+ min-width: calc(2ch + 0.25em);
185
+ }
160
186
  `;
@@ -0,0 +1 @@
1
+ export declare const useAllowedPattern: (allowedPattern: string | RegExp) => (<T extends InputEvent>(e: T) => void) | undefined;
@@ -0,0 +1,12 @@
1
+ import { useMemo } from 'haunted';
2
+ export const useAllowedPattern = (allowedPattern) => useMemo(() => {
3
+ if (allowedPattern == null) {
4
+ return;
5
+ }
6
+ const regexp = new RegExp(allowedPattern, 'u');
7
+ return (e) => {
8
+ if (!e.defaultPrevented && e.data && !regexp.test(e.data)) {
9
+ e.preventDefault();
10
+ }
11
+ };
12
+ }, [allowedPattern]);
@@ -0,0 +1,2 @@
1
+ import { BaseInput } from './use-input';
2
+ export declare const useAutoHeight: <T extends BaseInput>(host: T) => void;
@@ -0,0 +1,25 @@
1
+ import { useEffect, useMemo } from 'haunted';
2
+ const autoheight = (input) => {
3
+ input.style.height = '';
4
+ input.style.height = `${input.scrollHeight}px`;
5
+ };
6
+ const limit = (input, maxRows = 0) => {
7
+ if (maxRows > 0) {
8
+ const rows = input.getAttribute('rows') ?? '', height = input.style.height;
9
+ input.style.height = '';
10
+ input.setAttribute('rows', maxRows);
11
+ input.style.maxHeight = input.getBoundingClientRect().height + 'px';
12
+ input.style.height = height;
13
+ input.setAttribute('rows', rows);
14
+ }
15
+ };
16
+ export const useAutoHeight = (host) => {
17
+ const { value, maxRows } = host, input = useMemo(() => () => host.shadowRoot.querySelector('#input'), []);
18
+ useEffect(() => limit(input(), maxRows), [maxRows, input]);
19
+ useEffect(() => autoheight(input()), [input, value]);
20
+ useEffect(() => {
21
+ const el = input(), observer = new ResizeObserver(() => requestAnimationFrame(() => autoheight(el)));
22
+ observer.observe(el);
23
+ return () => observer.unobserve(el);
24
+ }, [input]);
25
+ };
@@ -8,4 +8,4 @@ export declare const useInput: <T extends BaseInput>(host: T) => {
8
8
  onChange: (e: Event) => boolean;
9
9
  onFocus: (e: FocusEvent) => void;
10
10
  onInput: (e: InputEvent) => void;
11
- }, useAllowedPattern: (allowedPattern: string | RegExp) => (<T extends InputEvent>(e: T) => void) | undefined, autosize: (input: HTMLElement) => void, limit: (input: HTMLElement, maxRows?: number) => void, useAutosize: <T extends BaseInput>(host: T) => void;
11
+ };
package/dist/use-input.js CHANGED
@@ -1,4 +1,4 @@
1
- import { useCallback, useEffect, useMemo } from 'haunted';
1
+ import { useCallback, useEffect } from 'haunted';
2
2
  import { useImperativeApi } from '@neovici/cosmoz-utils/hooks/use-imperative-api';
3
3
  import { notifyProperty } from '@neovici/cosmoz-utils/hooks/use-notify-property';
4
4
  // TODO: use useRef instead of callback with querySelector
@@ -30,35 +30,4 @@ export const useInput = (host) => {
30
30
  onFocus,
31
31
  onInput,
32
32
  };
33
- }, useAllowedPattern = (allowedPattern) => useMemo(() => {
34
- if (allowedPattern == null) {
35
- return;
36
- }
37
- const regexp = new RegExp(allowedPattern, 'u');
38
- return (e) => {
39
- if (!e.defaultPrevented && e.data && !regexp.test(e.data)) {
40
- e.preventDefault();
41
- }
42
- };
43
- }, [allowedPattern]), autosize = (input) => {
44
- input.style.height = '';
45
- input.style.height = `${input.scrollHeight}px`;
46
- }, limit = (input, maxRows = 0) => {
47
- if (maxRows > 0) {
48
- const rows = input.getAttribute('rows') ?? '', height = input.style.height;
49
- input.style.height = '';
50
- input.setAttribute('rows', maxRows);
51
- input.style.maxHeight = input.getBoundingClientRect().height + 'px';
52
- input.style.height = height;
53
- input.setAttribute('rows', rows);
54
- }
55
- }, useAutosize = (host) => {
56
- const { value, maxRows } = host, input = useMemo(() => () => host.shadowRoot.querySelector('#input'), []);
57
- useEffect(() => limit(input(), maxRows), [maxRows, input]);
58
- useEffect(() => autosize(input()), [input, value]);
59
- useEffect(() => {
60
- const el = input(), observer = new ResizeObserver(() => requestAnimationFrame(() => autosize(el)));
61
- observer.observe(el);
62
- return () => observer.unobserve(el);
63
- }, [input]);
64
33
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neovici/cosmoz-input",
3
- "version": "3.2.0",
3
+ "version": "3.4.0",
4
4
  "description": "A input web component",
5
5
  "keywords": [
6
6
  "lit-html",