@neovici/cosmoz-input 1.6.1 → 2.0.0-beta.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/cosmoz-input.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { html } from 'lit-html'; // eslint-disable-line object-curly-newline
2
- import { live } from 'lit-html/directives/live';
3
- import { ifDefined } from 'lit-html/directives/if-defined';
2
+ import { live } from 'lit-html/directives/live.js';
3
+ import { ifDefined } from 'lit-html/directives/if-defined.js';
4
4
 
5
5
  import { component } from 'haunted';
6
6
  import { useInput, useAllowedPattern } from './use-input';
7
7
  import { render, attributes } from './render';
8
8
 
9
- export const Input = host => {
9
+ export const Input = (host) => {
10
10
  const {
11
11
  type = 'text',
12
12
  pattern,
@@ -18,21 +18,36 @@ export const Input = host => {
18
18
  disabled,
19
19
  min,
20
20
  max,
21
- step
21
+ step,
22
+ maxlength,
22
23
  } = host,
23
24
  { onChange, onFocus, onInput } = useInput(host),
24
25
  onBeforeInput = useAllowedPattern(allowedPattern);
25
- return render(html`<input id="input" part="input"
26
- type=${ type } pattern=${ ifDefined(pattern) }
27
- autocomplete=${ ifDefined(autocomplete) } placeholder=${ placeholder || ' ' }
28
- ?readonly=${ readonly } ?aria-disabled=${ disabled } ?disabled=${ disabled }
29
- .value=${ live(value ?? '') }
30
- @beforeinput=${ onBeforeInput } @input=${ onInput }
31
- @change=${ onChange } @focus=${ onFocus } @blur=${ onFocus }
32
- min=${ ifDefined(min) } max=${ ifDefined(max) } step=${ifDefined(step)} >`
33
- , host);
26
+ return render(
27
+ html`<input
28
+ id="input"
29
+ part="input"
30
+ type=${type}
31
+ pattern=${ifDefined(pattern)}
32
+ autocomplete=${ifDefined(autocomplete)}
33
+ placeholder=${placeholder || ' '}
34
+ ?readonly=${readonly}
35
+ ?aria-disabled=${disabled}
36
+ ?disabled=${disabled}
37
+ .value=${live(value ?? '')}
38
+ maxlength=${ifDefined(maxlength)}
39
+ @beforeinput=${onBeforeInput}
40
+ @input=${onInput}
41
+ @change=${onChange}
42
+ @focus=${onFocus}
43
+ @blur=${onFocus}
44
+ min=${ifDefined(min)}
45
+ max=${ifDefined(max)}
46
+ step=${ifDefined(step)}
47
+ />`,
48
+ host
49
+ );
34
50
  },
35
-
36
51
  observedAttributes = [
37
52
  'type',
38
53
  'pattern',
@@ -40,7 +55,7 @@ export const Input = host => {
40
55
  'min',
41
56
  'max',
42
57
  'step',
43
- ...attributes
58
+ ...attributes,
44
59
  ];
45
60
 
46
61
  customElements.define('cosmoz-input', component(Input, { observedAttributes }));
@@ -1,12 +1,12 @@
1
1
  import { html } from 'lit-html'; // eslint-disable-line object-curly-newline
2
- import { live } from 'lit-html/directives/live';
3
- import { ifDefined } from 'lit-html/directives/if-defined';
2
+ import { live } from 'lit-html/directives/live.js';
3
+ import { ifDefined } from 'lit-html/directives/if-defined.js';
4
4
 
5
5
  import { component } from 'haunted';
6
6
  import { useInput, useAutosize } from './use-input';
7
7
  import { render, attributes } from './render';
8
8
 
9
- export const Textarea = host => {
9
+ export const Textarea = (host) => {
10
10
  const {
11
11
  autocomplete,
12
12
  value,
@@ -14,24 +14,28 @@ export const Textarea = host => {
14
14
  readonly,
15
15
  disabled,
16
16
  rows,
17
- cols
17
+ cols,
18
+ maxlength,
18
19
  } = host,
19
20
  { onChange, onFocus, onInput } = useInput(host);
20
21
 
21
22
  useAutosize(host);
22
23
 
23
- return render(html`
24
+ return render(
25
+ html`
24
26
  <textarea id="input" part="input" style="resize: none"
25
- autocomplete=${ ifDefined(autocomplete) } placeholder=${ placeholder || ' ' } rows=${ rows ?? 1 } cols=${ ifDefined(cols) }
26
- ?readonly=${ readonly } ?aria-disabled=${ disabled } ?disabled=${ disabled }
27
- .value=${ live(value ?? '') } @input=${ onInput }
28
- @change=${ onChange } @focus=${ onFocus } @blur=${ onFocus }>`
29
- , host);
27
+ autocomplete=${ifDefined(autocomplete)} placeholder=${
28
+ placeholder || ' '
29
+ } rows=${rows ?? 1} cols=${ifDefined(cols)}
30
+ ?readonly=${readonly} ?aria-disabled=${disabled} ?disabled=${disabled}
31
+ .value=${live(value ?? '')} maxlength=${ifDefined(maxlength)} @input=${onInput}
32
+ @change=${onChange} @focus=${onFocus} @blur=${onFocus}>`,
33
+ host
34
+ );
30
35
  },
36
+ observedAttributes = ['rows', ...attributes];
31
37
 
32
- observedAttributes = [
33
- 'rows',
34
- ...attributes
35
- ];
36
-
37
- customElements.define('cosmoz-textarea', component(Textarea, { observedAttributes }));
38
+ customElements.define(
39
+ 'cosmoz-textarea',
40
+ component(Textarea, { observedAttributes })
41
+ );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neovici/cosmoz-input",
3
- "version": "1.6.1",
3
+ "version": "2.0.0-beta.1",
4
4
  "description": "A input web component",
5
5
  "keywords": [
6
6
  "lit-html",
@@ -23,11 +23,10 @@
23
23
  "scripts": {
24
24
  "lint": "eslint --cache --ext .js .",
25
25
  "lint-tsc": "tsc",
26
- "start": "npm run storybook",
26
+ "start": "wds",
27
27
  "test": "wtr --coverage",
28
28
  "test:watch": "wtr --watch",
29
29
  "prepare": "husky install",
30
- "storybook": "start-storybook --node-resolve --watch --open",
31
30
  "storybook:build": "build-storybook",
32
31
  "storybook:deploy": "storybook-to-ghpages"
33
32
  },
@@ -56,22 +55,22 @@
56
55
  ]
57
56
  },
58
57
  "dependencies": {
59
- "@neovici/cosmoz-utils": "^3.23.0",
60
- "haunted": "^4.8.0",
61
- "lit-html": "^1.4.0"
58
+ "@neovici/cosmoz-utils": "^4.0.0-beta.2",
59
+ "haunted": "^5.0.0",
60
+ "lit-html": "^2.0.0"
62
61
  },
63
62
  "devDependencies": {
64
- "@commitlint/cli": "^16.0.0",
65
- "@commitlint/config-conventional": "^16.0.0",
63
+ "@commitlint/cli": "^17.0.0",
64
+ "@commitlint/config-conventional": "^17.0.0",
66
65
  "@neovici/cfg": "^1.13.1",
67
- "@open-wc/demoing-storybook": "^2.1.0",
68
- "@open-wc/testing": "^2.5.0",
66
+ "@open-wc/testing": "^3.0.0",
69
67
  "@semantic-release/changelog": "^6.0.0",
70
68
  "@semantic-release/git": "^10.0.0",
71
69
  "@storybook/storybook-deployer": "^2.8.5",
72
- "husky": "^7.0.0",
70
+ "@web/dev-server-storybook": "^0.5.1",
71
+ "husky": "^8.0.0",
73
72
  "semantic-release": "^19.0.0",
74
- "sinon": "^13.0.0",
73
+ "sinon": "^14.0.0",
75
74
  "typescript": "^4.6.0"
76
75
  }
77
76
  }
package/render.js CHANGED
@@ -2,24 +2,31 @@ import { html, nothing } from 'lit-html';
2
2
  import { styles } from './styles';
3
3
 
4
4
  export const render = (control, { label, invalid, errorMessage }) => html`
5
- <style>${ styles }</style>
5
+ <style>
6
+ ${styles}
7
+ </style>
6
8
  <div class="float" part="float">&nbsp;</div>
7
9
  <div class="wrap" part="wrap">
8
10
  <slot name="prefix"></slot>
9
11
  <div class="control" part="control">
10
- ${ control }
11
- ${ label ? html`<label for="input" part="label">${ label }</label>` : nothing }
12
+ ${control}
13
+ ${label
14
+ ? html`<label for="input" part="label">${label}</label>`
15
+ : nothing}
12
16
  </div>
13
17
  <slot name="suffix"></slot>
14
18
  </div>
15
19
  <div class="line" part="line"></div>
16
- ${ invalid && errorMessage ? html`<div class="error" part="error">${ errorMessage }</div>` : nothing }
17
- `,
20
+ ${invalid && errorMessage
21
+ ? html`<div class="error" part="error">${errorMessage}</div>`
22
+ : nothing}
23
+ `,
18
24
  attributes = [
19
25
  'autocomplete',
20
26
  'readonly',
21
27
  'disabled',
28
+ 'maxlength',
22
29
  'invalid',
23
30
  'no-label-float',
24
- 'always-float-label'
31
+ 'always-float-label',
25
32
  ];
package/styles.js CHANGED
@@ -1,20 +1,43 @@
1
- export const styles = `
1
+ import { tagged as css } from '@neovici/cosmoz-utils';
2
+ export const styles = css`
2
3
  :host {
3
- --font-family: var(--cosmoz-input-font-family, var(--paper-font-subhead_-_font-family, 'Roboto', 'Noto', sans-serif));
4
- --font-size: var(--cosmoz-input-font-size, var(--paper-font-subhead_-_font-size, 16px));
5
- --line-height: var(--cosmoz-input-line-height, var(--paper-font-subhead_-_line-height, 24px));
4
+ --font-family: var(
5
+ --cosmoz-input-font-family,
6
+ var(--paper-font-subhead_-_font-family, 'Roboto', 'Noto', sans-serif)
7
+ );
8
+ --font-size: var(
9
+ --cosmoz-input-font-size,
10
+ var(--paper-font-subhead_-_font-size, 16px)
11
+ );
12
+ --line-height: var(
13
+ --cosmoz-input-line-height,
14
+ var(--paper-font-subhead_-_line-height, 24px)
15
+ );
6
16
  --label-scale: var(--cosmoz-input-label-scale, 0.75);
7
- --disabled-opacity: var(--cosmoz-input-disabled-opacity, var(--paper-input-container-disabled_-_opacity, 0.33));
8
- --disabled-line-opacity: var(--cosmoz-input-disabled-line-opacity, var(--paper-input-container-underline-disabled_-_opacity, 1));
9
- --invalid-color: var(--cosmoz-input-invalid-color, var(--paper-input-container-invalid-color, var(--error-color, #fc5c5b)));
17
+ --disabled-opacity: var(
18
+ --cosmoz-input-disabled-opacity,
19
+ var(--paper-input-container-disabled_-_opacity, 0.33)
20
+ );
21
+ --disabled-line-opacity: var(
22
+ --cosmoz-input-disabled-line-opacity,
23
+ var(--paper-input-container-underline-disabled_-_opacity, 1)
24
+ );
25
+ --invalid-color: var(
26
+ --cosmoz-input-invalid-color,
27
+ var(--paper-input-container-invalid-color, var(--error-color, #fc5c5b))
28
+ );
10
29
  --bg: var(--cosmoz-input-background);
11
30
  --focused-bg: var(--cosmoz-input-focused-background, var(--bg));
12
31
  --color: var(--cosmoz-input-color, var(--secondary-text-color, #737373));
13
- --focused-color: var(--cosmoz-input-focused-color, var(--primary-color, #3f51b5));
32
+ --focused-color: var(
33
+ --cosmoz-input-focused-color,
34
+ var(--primary-color, #3f51b5)
35
+ );
14
36
 
15
37
  display: block;
16
- padding: 8px 0;
38
+ padding: var(--cosmoz-input-padding, 8px 0);
17
39
  padding-top: var(--paper-input-container_-_padding-top, 8px);
40
+ padding-bottom: var(--paper-input-container_-_padding-bottom, 8px);
18
41
  position: relative;
19
42
 
20
43
  font-family: var(--font-family);
@@ -73,7 +96,8 @@ export const styles = `
73
96
 
74
97
  :host([always-float-label]) label,
75
98
  #input:not(:placeholder-shown) + label {
76
- transform: translateY(calc(var(--label-scale) * -100%)) scale(var(--label-scale));
99
+ transform: translateY(calc(var(--label-scale) * -100%))
100
+ scale(var(--label-scale));
77
101
  }
78
102
  #input:not(:placeholder-shown):focus + label {
79
103
  color: var(--focused-color);
@@ -93,7 +117,7 @@ export const styles = `
93
117
  left: 0;
94
118
  right: 0;
95
119
  top: 0;
96
- transform: scale3d(0,1,1);
120
+ transform: scale3d(0, 1, 1);
97
121
  transform-origin: center center;
98
122
  z-index: 1;
99
123
  }
@@ -102,7 +126,7 @@ export const styles = `
102
126
  transition: 0.25s transform ease;
103
127
  }
104
128
  :host(:focus-within) .line {
105
- border-bottom-color: var(--focused-color);
129
+ border-bottom-color: var(--focused-color);
106
130
  }
107
131
  :host([disabled]) .line {
108
132
  border-bottom-style: dashed;
@@ -110,7 +134,7 @@ export const styles = `
110
134
  }
111
135
 
112
136
  :host([no-label-float]) .float,
113
- :host([no-label-float]) #input:not(:placeholder-shown) + label {
137
+ :host([no-label-float]) #input:not(:placeholder-shown) + label {
114
138
  display: none;
115
139
  }
116
140
 
@@ -122,7 +146,8 @@ export const styles = `
122
146
  position: absolute;
123
147
  max-width: 100%;
124
148
  }
125
- :host([invalid]) label, .error {
149
+ :host([invalid]) label,
150
+ .error {
126
151
  color: var(--invalid-color);
127
152
  }
128
153
  :host([invalid]) .line {
package/use-input.js CHANGED
@@ -2,11 +2,20 @@ import { useCallback, useEffect, useMemo } from 'haunted';
2
2
  import { useImperativeApi } from '@neovici/cosmoz-utils/lib/hooks/use-imperative-api';
3
3
  import { notifyProperty } from '@neovici/cosmoz-utils/lib/hooks/use-notify-property';
4
4
 
5
- export const useInput = host => {
5
+ export const useInput = (host) => {
6
6
  const root = host.shadowRoot,
7
- onChange = useCallback(e => host.dispatchEvent(new Event(e.type, { bubbles: e.bubbles })), []),
8
- onInput = useCallback(e => notifyProperty(host, 'value', e.target.value), []),
9
- onFocus = useCallback(e => notifyProperty(host, 'focused', e.type === 'focus'), []),
7
+ onChange = useCallback(
8
+ (e) => host.dispatchEvent(new Event(e.type, { bubbles: e.bubbles })),
9
+ []
10
+ ),
11
+ onInput = useCallback(
12
+ (e) => notifyProperty(host, 'value', e.target.value),
13
+ []
14
+ ),
15
+ onFocus = useCallback(
16
+ (e) => notifyProperty(host, 'focused', e.type === 'focus'),
17
+ []
18
+ ),
10
19
  focus = useCallback(() => root.querySelector('#input')?.focus(), []),
11
20
  validate = useCallback(() => {
12
21
  const valid = root.querySelector('#input')?.checkValidity();
@@ -17,12 +26,13 @@ export const useInput = host => {
17
26
  useImperativeApi({ focus, validate }, [focus, validate]);
18
27
 
19
28
  useEffect(() => {
20
- const onMouseDown = e => {
29
+ const onMouseDown = (e) => {
21
30
  if (e.defaultPrevented || e.target.matches('input, textarea, label')) {
22
31
  return;
23
32
  }
24
33
  e.preventDefault(); // don't blur
25
- if (!host.matches(':focus-within')) { // if input not focused
34
+ if (!host.matches(':focus-within')) {
35
+ // if input not focused
26
36
  focus(); // focus input
27
37
  }
28
38
  };
@@ -34,24 +44,24 @@ export const useInput = host => {
34
44
  return {
35
45
  onChange,
36
46
  onFocus,
37
- onInput
47
+ onInput,
38
48
  };
39
49
  },
40
- useAllowedPattern = allowedPattern => useMemo(() => {
41
- if (allowedPattern == null) {
42
- return;
43
- }
44
- const regexp = new RegExp(allowedPattern, 'u');
45
- return e => {
46
- if (!e.defaultPrevent && e.data && !regexp.test(e.data)) {
47
- e.preventDefault();
50
+ useAllowedPattern = (allowedPattern) =>
51
+ useMemo(() => {
52
+ if (allowedPattern == null) {
53
+ return;
48
54
  }
49
-
50
- };
51
- }, [allowedPattern]),
52
- autosize = input => {
55
+ const regexp = new RegExp(allowedPattern, 'u');
56
+ return (e) => {
57
+ if (!e.defaultPrevent && e.data && !regexp.test(e.data)) {
58
+ e.preventDefault();
59
+ }
60
+ };
61
+ }, [allowedPattern]),
62
+ autosize = (input) => {
53
63
  input.style.height = '';
54
- input.style.height = `${ input.scrollHeight }px`;
64
+ input.style.height = `${input.scrollHeight}px`;
55
65
  },
56
66
  limit = (input, maxRows) => {
57
67
  if (maxRows > 0) {
@@ -64,16 +74,17 @@ export const useInput = host => {
64
74
  input.setAttribute('rows', rows);
65
75
  }
66
76
  },
67
- useAutosize = host => {
77
+ useAutosize = (host) => {
68
78
  const { value, maxRows } = host,
69
79
  input = useMemo(() => () => host.shadowRoot.querySelector('#input'), []);
70
80
  useEffect(() => limit(input(), maxRows), [maxRows, input]);
71
81
  useEffect(() => autosize(input()), [input, value]);
72
82
  useEffect(() => {
73
83
  const el = input(),
74
- observer = new ResizeObserver(() => requestAnimationFrame(() => autosize(el)));
84
+ observer = new ResizeObserver(() =>
85
+ requestAnimationFrame(() => autosize(el))
86
+ );
75
87
  observer.observe(el);
76
88
  return () => observer.unobserve(el);
77
89
  }, [input]);
78
-
79
90
  };
@@ -1,8 +0,0 @@
1
- /* eslint-env node */
2
- module.exports = {
3
- appIndex: 'demo/index.html',
4
- open: true,
5
- preserveSymlinks: true,
6
- dedupe: true,
7
- nodeResolve: { mainFields: ['browser', 'jsnext', 'jsnext:main', 'module', 'main']}
8
- };