@neovici/cosmoz-input 2.0.0 → 3.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neovici/cosmoz-input",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "A input web component",
5
5
  "keywords": [
6
6
  "lit-html",
@@ -16,13 +16,16 @@
16
16
  },
17
17
  "license": "Apache-2.0",
18
18
  "author": "",
19
- "main": "cosmoz-input.js",
19
+ "main": "dist/index.js",
20
20
  "directories": {
21
21
  "test": "test"
22
22
  },
23
+ "files": [
24
+ "dist/"
25
+ ],
23
26
  "scripts": {
24
- "lint": "eslint --cache --ext .js .",
25
- "lint-tsc": "tsc",
27
+ "lint": "tsc && eslint --cache .",
28
+ "build": "tsc -p tsconfig.build.json",
26
29
  "start": "wds",
27
30
  "test": "wtr --coverage",
28
31
  "test:watch": "wtr --watch",
@@ -45,10 +48,6 @@
45
48
  "publishConfig": {
46
49
  "access": "public"
47
50
  },
48
- "files": [
49
- "*.js",
50
- "lib/**/*.js"
51
- ],
52
51
  "commitlint": {
53
52
  "extends": [
54
53
  "@commitlint/config-conventional"
@@ -61,8 +60,14 @@
61
60
  ]
62
61
  }
63
62
  },
63
+ "exports": {
64
+ ".": "./dist/index.js",
65
+ "./use-input": "./dist/use-input.js",
66
+ "./input": "./dist/cosmoz-input.js",
67
+ "./textarea": "./dist/cosmoz-textarea.js"
68
+ },
64
69
  "dependencies": {
65
- "@neovici/cosmoz-utils": "^4.0.0",
70
+ "@neovici/cosmoz-utils": "^5.1.0",
66
71
  "haunted": "^5.0.0",
67
72
  "lit-html": "^2.0.0"
68
73
  },
package/cosmoz-input.js DELETED
@@ -1,61 +0,0 @@
1
- import { html } from 'lit-html'; // eslint-disable-line object-curly-newline
2
- import { live } from 'lit-html/directives/live.js';
3
- import { ifDefined } from 'lit-html/directives/if-defined.js';
4
-
5
- import { component } from 'haunted';
6
- import { useInput, useAllowedPattern } from './use-input';
7
- import { render, attributes } from './render';
8
-
9
- export const Input = (host) => {
10
- const {
11
- type = 'text',
12
- pattern,
13
- allowedPattern,
14
- autocomplete,
15
- value,
16
- placeholder,
17
- readonly,
18
- disabled,
19
- min,
20
- max,
21
- step,
22
- maxlength,
23
- } = host,
24
- { onChange, onFocus, onInput } = useInput(host),
25
- onBeforeInput = useAllowedPattern(allowedPattern);
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
- );
50
- },
51
- observedAttributes = [
52
- 'type',
53
- 'pattern',
54
- 'allowed-pattern',
55
- 'min',
56
- 'max',
57
- 'step',
58
- ...attributes,
59
- ];
60
-
61
- customElements.define('cosmoz-input', component(Input, { observedAttributes }));
@@ -1,41 +0,0 @@
1
- import { html } from 'lit-html'; // eslint-disable-line object-curly-newline
2
- import { live } from 'lit-html/directives/live.js';
3
- import { ifDefined } from 'lit-html/directives/if-defined.js';
4
-
5
- import { component } from 'haunted';
6
- import { useInput, useAutosize } from './use-input';
7
- import { render, attributes } from './render';
8
-
9
- export const Textarea = (host) => {
10
- const {
11
- autocomplete,
12
- value,
13
- placeholder,
14
- readonly,
15
- disabled,
16
- rows,
17
- cols,
18
- maxlength,
19
- } = host,
20
- { onChange, onFocus, onInput } = useInput(host);
21
-
22
- useAutosize(host);
23
-
24
- return render(
25
- html`
26
- <textarea id="input" part="input" style="resize: none"
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
- );
35
- },
36
- observedAttributes = ['rows', ...attributes];
37
-
38
- customElements.define(
39
- 'cosmoz-textarea',
40
- component(Textarea, { observedAttributes })
41
- );
package/render.js DELETED
@@ -1,32 +0,0 @@
1
- import { html, nothing } from 'lit-html';
2
- import { styles } from './styles';
3
-
4
- export const render = (control, { label, invalid, errorMessage }) => html`
5
- <style>
6
- ${styles}
7
- </style>
8
- <div class="float" part="float">&nbsp;</div>
9
- <div class="wrap" part="wrap">
10
- <slot name="prefix"></slot>
11
- <div class="control" part="control">
12
- ${control}
13
- ${label
14
- ? html`<label for="input" part="label">${label}</label>`
15
- : nothing}
16
- </div>
17
- <slot name="suffix"></slot>
18
- </div>
19
- <div class="line" part="line"></div>
20
- ${invalid && errorMessage
21
- ? html`<div class="error" part="error">${errorMessage}</div>`
22
- : nothing}
23
- `,
24
- attributes = [
25
- 'autocomplete',
26
- 'readonly',
27
- 'disabled',
28
- 'maxlength',
29
- 'invalid',
30
- 'no-label-float',
31
- 'always-float-label',
32
- ];
package/styles.js DELETED
@@ -1,160 +0,0 @@
1
- import { tagged as css } from '@neovici/cosmoz-utils';
2
- export const styles = css`
3
- :host {
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
- );
16
- --label-scale: var(--cosmoz-input-label-scale, 0.75);
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
- );
29
- --bg: var(--cosmoz-input-background);
30
- --focused-bg: var(--cosmoz-input-focused-background, var(--bg));
31
- --color: var(--cosmoz-input-color, var(--secondary-text-color, #737373));
32
- --focused-color: var(
33
- --cosmoz-input-focused-color,
34
- var(--primary-color, #3f51b5)
35
- );
36
-
37
- display: block;
38
- padding: var(--cosmoz-input-padding, 8px 0);
39
- padding-top: var(--paper-input-container_-_padding-top, 8px);
40
- padding-bottom: var(--paper-input-container_-_padding-bottom, 8px);
41
- position: relative;
42
-
43
- font-family: var(--font-family);
44
- font-size: var(--font-size);
45
- line-height: var(--line-height);
46
- }
47
-
48
- :host([disabled]) {
49
- opacity: var(--disabled-opacity);
50
- pointer-events: none;
51
- }
52
-
53
- .float {
54
- line-height: calc(var(--line-height) * var(--label-scale));
55
- }
56
-
57
- .wrap {
58
- display: flex;
59
- align-items: center;
60
- position: relative;
61
- }
62
-
63
- .control {
64
- flex: 1;
65
- position: relative;
66
- }
67
-
68
- #input {
69
- padding: 0;
70
- margin: 0;
71
- outline: none;
72
- border: none;
73
- width: 100%;
74
- max-width: 100%;
75
- display: block;
76
- background: var(--bg);
77
- line-height: inherit;
78
- font-size: inherit;
79
- }
80
-
81
- :host(:focus-within) #input {
82
- background: var(--focused-bg);
83
- }
84
- label {
85
- position: absolute;
86
- top: 0;
87
- left: 0;
88
- width: 100%;
89
- transition: transform 0.25s, width 0.25s;
90
- transform-origin: left top;
91
- color: var(--color);
92
- white-space: nowrap;
93
- overflow: hidden;
94
- text-overflow: ellipsis;
95
- }
96
-
97
- :host([always-float-label]) label,
98
- #input:not(:placeholder-shown) + label {
99
- transform: translateY(calc(var(--label-scale) * -100%))
100
- scale(var(--label-scale));
101
- }
102
- #input:not(:placeholder-shown):focus + label {
103
- color: var(--focused-color);
104
- }
105
-
106
- .line {
107
- padding-top: 1px;
108
- border-bottom: 1px solid var(--color);
109
- position: relative;
110
- }
111
- .line::before {
112
- content: '';
113
- position: absolute;
114
- display: block;
115
- border-bottom: 2px solid transparent;
116
- border-bottom-color: inherit;
117
- left: 0;
118
- right: 0;
119
- top: 0;
120
- transform: scale3d(0, 1, 1);
121
- transform-origin: center center;
122
- z-index: 1;
123
- }
124
- :host(:focus-within) .line::before {
125
- transform: none;
126
- transition: 0.25s transform ease;
127
- }
128
- :host(:focus-within) .line {
129
- border-bottom-color: var(--focused-color);
130
- }
131
- :host([disabled]) .line {
132
- border-bottom-style: dashed;
133
- opacity: var(--disabled-line-opacity);
134
- }
135
-
136
- :host([no-label-float]) .float,
137
- :host([no-label-float]) #input:not(:placeholder-shown) + label {
138
- display: none;
139
- }
140
-
141
- .error {
142
- font-size: 12px;
143
- line-height: 20px;
144
- overflow: hidden;
145
- text-overflow: clip;
146
- position: absolute;
147
- max-width: 100%;
148
- }
149
- :host([invalid]) label,
150
- .error {
151
- color: var(--invalid-color);
152
- }
153
- :host([invalid]) .line {
154
- border-bottom-color: var(--invalid-color);
155
- }
156
-
157
- #input::-webkit-inner-spin-button {
158
- z-index: 1;
159
- }
160
- `;
package/use-input.js DELETED
@@ -1,90 +0,0 @@
1
- import { useCallback, useEffect, useMemo } from 'haunted';
2
- import { useImperativeApi } from '@neovici/cosmoz-utils/lib/hooks/use-imperative-api';
3
- import { notifyProperty } from '@neovici/cosmoz-utils/lib/hooks/use-notify-property';
4
-
5
- export const useInput = (host) => {
6
- const root = host.shadowRoot,
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
- ),
19
- focus = useCallback(() => root.querySelector('#input')?.focus(), []),
20
- validate = useCallback(() => {
21
- const valid = root.querySelector('#input')?.checkValidity();
22
- host.toggleAttribute('invalid', !valid);
23
- return valid;
24
- }, []);
25
-
26
- useImperativeApi({ focus, validate }, [focus, validate]);
27
-
28
- useEffect(() => {
29
- const onMouseDown = (e) => {
30
- if (e.defaultPrevented || e.target.matches('input, textarea, label')) {
31
- return;
32
- }
33
- e.preventDefault(); // don't blur
34
- if (!host.matches(':focus-within')) {
35
- // if input not focused
36
- focus(); // focus input
37
- }
38
- };
39
-
40
- root.addEventListener('mousedown', onMouseDown);
41
- return () => root.removeEventListener('mousedown', onMouseDown);
42
- }, [focus]);
43
-
44
- return {
45
- onChange,
46
- onFocus,
47
- onInput,
48
- };
49
- },
50
- useAllowedPattern = (allowedPattern) =>
51
- useMemo(() => {
52
- if (allowedPattern == null) {
53
- return;
54
- }
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) => {
63
- input.style.height = '';
64
- input.style.height = `${input.scrollHeight}px`;
65
- },
66
- limit = (input, maxRows) => {
67
- if (maxRows > 0) {
68
- const rows = input.getAttribute('rows'),
69
- height = input.style.height;
70
- input.style.height = '';
71
- input.setAttribute('rows', maxRows);
72
- input.style.maxHeight = input.getBoundingClientRect().height + 'px';
73
- input.style.height = height;
74
- input.setAttribute('rows', rows);
75
- }
76
- },
77
- useAutosize = (host) => {
78
- const { value, maxRows } = host,
79
- input = useMemo(() => () => host.shadowRoot.querySelector('#input'), []);
80
- useEffect(() => limit(input(), maxRows), [maxRows, input]);
81
- useEffect(() => autosize(input()), [input, value]);
82
- useEffect(() => {
83
- const el = input(),
84
- observer = new ResizeObserver(() =>
85
- requestAnimationFrame(() => autosize(el))
86
- );
87
- observer.observe(el);
88
- return () => observer.unobserve(el);
89
- }, [input]);
90
- };