@esportsplus/ui 0.24.5 → 0.25.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.
Files changed (76) hide show
  1. package/build/components/checkbox/index.d.ts +11 -0
  2. package/build/components/checkbox/index.js +33 -0
  3. package/build/components/checkbox/scss/index.scss +2 -0
  4. package/build/components/index.d.ts +7 -1
  5. package/build/components/index.js +7 -1
  6. package/build/components/input/index.d.ts +21 -0
  7. package/build/components/input/index.js +38 -0
  8. package/build/components/input/scss/index.scss +2 -0
  9. package/build/components/radio/index.d.ts +11 -0
  10. package/build/components/radio/index.js +33 -0
  11. package/build/components/radio/scss/index.scss +2 -0
  12. package/build/components/range/index.d.ts +21 -0
  13. package/build/components/range/index.js +46 -0
  14. package/build/components/range/scss/index.scss +2 -0
  15. package/build/components/select/index.d.ts +44 -0
  16. package/build/components/{field/select.js → select/index.js} +25 -52
  17. package/build/components/select/scss/index.scss +2 -0
  18. package/build/components/switch/index.d.ts +11 -0
  19. package/build/components/switch/index.js +33 -0
  20. package/build/components/switch/scss/index.scss +2 -0
  21. package/build/components/text/scss/index.scss +1 -1
  22. package/build/components/textarea/index.d.ts +21 -0
  23. package/build/components/textarea/index.js +37 -0
  24. package/build/components/textarea/scss/index.scss +2 -0
  25. package/build/normalize/scss/index.scss +1 -1
  26. package/package.json +2 -2
  27. package/src/components/checkbox/index.ts +45 -0
  28. package/src/components/checkbox/scss/index.scss +50 -0
  29. package/src/components/checkbox/scss/variables.scss +72 -0
  30. package/src/components/index.ts +7 -1
  31. package/src/components/input/index.ts +52 -0
  32. package/src/components/input/scss/index.scss +37 -0
  33. package/src/components/input/scss/variables.scss +50 -0
  34. package/src/components/radio/index.ts +45 -0
  35. package/src/components/radio/scss/index.scss +50 -0
  36. package/src/components/radio/scss/variables.scss +67 -0
  37. package/src/components/range/index.ts +61 -0
  38. package/src/components/range/scss/index.scss +31 -0
  39. package/src/components/range/scss/variables.scss +8 -0
  40. package/src/components/{field/select.ts → select/index.ts} +50 -106
  41. package/src/components/select/scss/index.scss +36 -0
  42. package/src/components/select/scss/variables.scss +12 -0
  43. package/src/components/switch/index.ts +45 -0
  44. package/src/components/switch/scss/index.scss +48 -0
  45. package/src/components/switch/scss/variables.scss +72 -0
  46. package/src/components/text/scss/index.scss +31 -0
  47. package/src/components/textarea/index.ts +51 -0
  48. package/src/components/textarea/scss/index.scss +26 -0
  49. package/src/components/textarea/scss/variables.scss +49 -0
  50. package/src/normalize/scss/index.scss +36 -1
  51. package/build/components/field/checkbox.d.ts +0 -73
  52. package/build/components/field/checkbox.js +0 -71
  53. package/build/components/field/description.d.ts +0 -19
  54. package/build/components/field/description.js +0 -7
  55. package/build/components/field/error.d.ts +0 -5
  56. package/build/components/field/error.js +0 -13
  57. package/build/components/field/index.d.ts +0 -17481
  58. package/build/components/field/index.js +0 -10
  59. package/build/components/field/input.d.ts +0 -156
  60. package/build/components/field/input.js +0 -97
  61. package/build/components/field/scss/index.scss +0 -2
  62. package/build/components/field/select.d.ts +0 -1350
  63. package/build/components/field/title.d.ts +0 -1169
  64. package/build/components/field/title.js +0 -20
  65. package/src/components/field/checkbox.ts +0 -97
  66. package/src/components/field/description.ts +0 -11
  67. package/src/components/field/error.ts +0 -16
  68. package/src/components/field/index.ts +0 -15
  69. package/src/components/field/input.ts +0 -134
  70. package/src/components/field/scss/check.scss +0 -227
  71. package/src/components/field/scss/index.scss +0 -133
  72. package/src/components/field/scss/normalize.scss +0 -34
  73. package/src/components/field/scss/range.scss +0 -46
  74. package/src/components/field/scss/text.scss +0 -120
  75. package/src/components/field/scss/variables.scss +0 -128
  76. package/src/components/field/title.ts +0 -27
@@ -1,33 +1,46 @@
1
1
  import { reactive } from '@esportsplus/reactivity';
2
- import { html, type Attributes, type Renderable } from '@esportsplus/template';
3
- import { isObject, omit, toArray } from '@esportsplus/utilities';
2
+ import { html, Renderable, type Attributes } from '@esportsplus/template';
3
+ import { omit, toArray } from '@esportsplus/utilities';
4
4
  import form from '~/components/form';
5
5
  import root from '~/components/root';
6
6
  import scrollbar, { Attributes as Attr } from '~/components/scrollbar';
7
7
  import template from '~/components/template';
8
- import error from './error';
8
+ import './scss/index.scss';
9
9
 
10
10
 
11
- const OMIT_FIELD = ['options', 'state'];
12
-
13
- const OMIT_MASK = [
14
- 'field-mask-arrow',
15
- 'field-mask-text',
16
- 'field-mask-tag',
11
+ const OMIT = [
12
+ 'options',
13
+ 'select-arrow',
14
+ 'select-tag',
15
+ 'select-text',
17
16
  'scrollbar',
18
17
  'scrollbar-container-content',
19
18
  'tooltip-content',
20
19
  ];
21
20
 
22
- const OMIT_OPTION = ['content'];
23
-
24
21
 
25
22
  type A = {
26
- 'field-mask-arrow'?: Attributes;
27
- 'field-mask-tag'?: Attributes;
28
- 'field-mask-text'?: Attributes;
23
+ 'select-arrow'?: Attributes;
24
+ 'select-tag'?: Attributes;
25
+ 'select-text'?: Attributes;
26
+ 'scrollbar'?: Attributes;
27
+ 'scrollbar-container-content'?: Attributes;
29
28
  'tooltip-content'?: Attributes & { direction?: string };
30
- } & Attributes & Attr;
29
+ options: Record<number | string, Renderable<unknown>>;
30
+ option?: Attributes;
31
+ } & (
32
+ {
33
+ selected?: number | string;
34
+ state?: never;
35
+ } | {
36
+ state: {
37
+ active: boolean;
38
+ error: string;
39
+ render: boolean;
40
+ selected?: number | string;
41
+ }
42
+ }
43
+ ) & Attributes & Attr;
31
44
 
32
45
 
33
46
  let field: { active: boolean } | null = null;
@@ -51,27 +64,20 @@ function set(state: { active: boolean }, value: boolean) {
51
64
  }
52
65
 
53
66
 
54
- const select = template.factory(
55
- function(
56
- this: {
57
- options: { content: unknown } & Attributes;
58
- option?: Attributes;
59
- state: {
60
- active: boolean;
61
- error: string;
62
- render: boolean;
63
- selected: string | number;
64
- }
65
- },
66
- attributes: A,
67
- content: Renderable<unknown>
68
- ) {
69
- let { option, options, state } = this;
67
+ export default template.factory<A>(
68
+ function(attributes: A, content) {
69
+ let { options, option } = attributes,
70
+ state = attributes.state || reactive({
71
+ active: false,
72
+ error: '',
73
+ render: false,
74
+ selected: attributes.selected || Object.keys(options)[0]
75
+ });
70
76
 
71
77
  return html`
72
78
  <label
73
- class='field-mask field-mask--select'
74
- ${omit(attributes, OMIT_MASK)}
79
+ class='select'
80
+ ${omit(attributes, OMIT)}
75
81
  ${{
76
82
  onclick: () => {
77
83
  if (state.render) {
@@ -82,26 +88,23 @@ const select = template.factory(
82
88
  }
83
89
  }}
84
90
  >
85
- <input class='field-mask-tag field-mask-tag--hidden'
91
+ <input class='select-tag'
86
92
  ${{
87
93
  name: attributes.name,
88
94
  onclick: () => { /* Prevent double click events from firing */ },
89
95
  onrender: form.input.onrender(state),
90
96
  value: () => state.selected
91
97
  }}
92
- ${attributes['field-mask-tag']}
98
+ ${attributes['select-tag']}
93
99
  >
94
100
 
95
101
  ${content || html`
96
- <div class='field-mask-text' ${attributes['field-mask-text']}>
97
- ${() => {
98
- // @ts-ignore
99
- return (options[ state.selected ]?.content || '-');
100
- }}
102
+ <div class='select-text' ${attributes['select-text']}>
103
+ ${() => options[ state.selected! ] || '-'}
101
104
  </div>
102
105
  `}
103
106
 
104
- <div class='field-mask-arrow' ${attributes['field-mask-arrow']}></div>
107
+ <div class='select-arrow' ${attributes['select-arrow']}></div>
105
108
 
106
109
  ${() => {
107
110
  if (!state.render) {
@@ -127,7 +130,7 @@ const select = template.factory(
127
130
  return;
128
131
  }
129
132
 
130
- let previous = state.selected;
133
+ let previous = state.selected!;
131
134
 
132
135
  set(state, false);
133
136
  state.selected = key;
@@ -142,16 +145,16 @@ const select = template.factory(
142
145
  'scrollbar-container-content': attributes['scrollbar-container-content']
143
146
  },
144
147
  keys.map((key) => html`
145
- <div class='link'
146
- ${omit(options[key] as Attributes, OMIT_OPTION)}
148
+ <div
149
+ class='link'
147
150
  ${option}
148
151
  ${{
152
+ 'data-key': key,
149
153
  class: () => selected[key] && '--active',
150
- 'data-key': key
151
154
  }}
152
155
  >
153
156
  <span class='--text-truncate --pointer-none'>
154
- ${(options[key] as any).content}
157
+ ${options[key]}
155
158
  </span>
156
159
  </div>
157
160
  `)
@@ -160,63 +163,4 @@ const select = template.factory(
160
163
  </label>
161
164
  `;
162
165
  }
163
- );
164
-
165
-
166
- export default template.factory<
167
- Attributes & {
168
- options: Record<number | string, (number | string | Attributes & { content: unknown })>;
169
- option?: Attributes;
170
- } & (
171
- {
172
- selected?: number | string;
173
- state?: never;
174
- } |
175
- {
176
- state: {
177
- active: boolean;
178
- error: string;
179
- render: boolean;
180
- selected?: number | string;
181
- }
182
- }
183
- ),
184
- (mask: typeof select) => Renderable<unknown>
185
- >((attributes, content) => {
186
- let options = attributes.options,
187
- state = attributes.state || reactive({
188
- active: false,
189
- error: '',
190
- render: false,
191
- selected: attributes.selected || Object.keys(options)[0]
192
- });
193
-
194
- for (let key in options) {
195
- if (isObject(options[key])) {
196
- continue;
197
- }
198
-
199
- options[key] = { content: options[key] };
200
- }
201
-
202
- return html`
203
- <div class='field tooltip'
204
- ${omit(attributes as any, OMIT_FIELD)}
205
- ${{
206
- class: () => state.active && '--active'
207
- }}
208
- >
209
- ${content(
210
- (...args: any[]) => (select.call as any)(
211
- {
212
- option: attributes.option,
213
- options: attributes.options,
214
- state
215
- },
216
- ...args
217
- )
218
- )}
219
- ${error(state)}
220
- </div>
221
- `;
222
- });
166
+ );
@@ -0,0 +1,36 @@
1
+ @use '/lib';
2
+
3
+ .select {
4
+ align-items: center;
5
+ background: var(--background);
6
+ border: var(--border-width) var(--border-style) var(--border-color);
7
+ border-radius: var(--border-radius);
8
+ cursor: pointer;
9
+ display: flex;
10
+ flex-wrap: wrap;
11
+ font-size: var(--font-size);
12
+ line-height: var(--line-height);
13
+ padding: var(--padding-vertical) calc((var(--padding-horizontal) / 1.5) + var(--arrow-size)) var(--padding-vertical) var(--padding-horizontal);
14
+ position: relative;
15
+ width: 100%;
16
+
17
+ &:invalid,
18
+ &:required {
19
+ box-shadow: none;
20
+ }
21
+
22
+ &-arrow {
23
+ @include lib.position(absolute, null calc(var(--padding-horizontal) + var(--arrow-spacer)) calc(50% + var(--arrow-spacer)) null);
24
+ border-color: var(--border-color);
25
+ border-style: var(--border-style);
26
+ border-width: 0 var(--border-width) var(--border-width) 0;
27
+ content: '';
28
+ height: var(--arrow-size);
29
+ transform: translateY(50%) rotate(45deg);
30
+ width: var(--arrow-size);
31
+ }
32
+
33
+ &-tag {
34
+ color: var(--color);
35
+ }
36
+ }
@@ -0,0 +1,12 @@
1
+ .select {
2
+ --arrow-spacer: 1px;
3
+ --arrow-size: 6px;
4
+ --font-size: var(--font-size-400);
5
+ --line-height: var(--line-height-400);
6
+ --padding-horizontal: var(--size-400);
7
+ --padding-vertical: var(--size-400);
8
+
9
+ &-arrow {
10
+ --border-width: var(--border-width-500);
11
+ }
12
+ }
@@ -0,0 +1,45 @@
1
+ import { reactive, root } from '@esportsplus/reactivity';
2
+ import { html, type Attributes } from '@esportsplus/template';
3
+ import { omit } from '@esportsplus/utilities';
4
+ import form from '~/components/form';
5
+ import './scss/index.scss';
6
+
7
+
8
+ type A = Attributes & {
9
+ 'switch-tag'?: Attributes,
10
+ state?: { active: boolean, error: string }
11
+ };
12
+
13
+
14
+ const OMIT = ['switch-tag'];
15
+
16
+
17
+ export default function(attributes?: A) {
18
+ let a = attributes?.['switch-tag'],
19
+ state = attributes?.state || reactive({
20
+ active: false,
21
+ error: ''
22
+ });
23
+
24
+ if (a?.checked) {
25
+ state.active = true;
26
+ }
27
+
28
+ return html`
29
+ <div class='switch' ${a ? omit(attributes!, OMIT) : attributes}>
30
+ <input
31
+ class='switch-tag'
32
+ type='checkbox'
33
+ ${{
34
+ checked: a?.checked || root(() => state.active),
35
+ onchange: (e: Event) => {
36
+ state.active = (e.target as HTMLInputElement).checked;
37
+ },
38
+ onrender: form.input.onrender(state),
39
+ value: a?.value || 1
40
+ }}
41
+ ${a}
42
+ >
43
+ </div>
44
+ `;
45
+ };
@@ -0,0 +1,48 @@
1
+ @use '/lib';
2
+ @use 'variables';
3
+
4
+ .switch {
5
+ background: var(--background);
6
+ border-color: var(--border-color);
7
+ border-radius: var(--border-radius);
8
+ border-style: var(--border-style);
9
+ border-width: var(--border-width);
10
+ flex: 0 0 var(--width);
11
+ height: var(--height);
12
+ position: relative;
13
+ transition:
14
+ background var(--transition-duration) ease-in-out,
15
+ border-color var(--transition-duration) ease-in-out,
16
+ box-shadow var(--transition-duration) ease-in-out,
17
+ opacity var(--transition-duration) ease-in-out,
18
+ transform var(--transition-duration) ease-in-out;
19
+ width: var(--width);
20
+
21
+ &:invalid,
22
+ &:required {
23
+ box-shadow: none;
24
+ }
25
+
26
+ &::before {
27
+ @include lib.position(absolute, var(--padding-vertical) null null var(--padding-horizontal));
28
+ background: var(--accent);
29
+ border-radius: inherit;
30
+ box-shadow: var(--box-shadow);
31
+ content: '';
32
+ height: var(--height);
33
+ opacity: var(--opacity);
34
+ transform: translate(var(--translateX), var(--translateY)) rotate(var(--rotate)) scale(var(--scale));
35
+ transform-origin: center;
36
+ width: var(--width);
37
+ }
38
+
39
+ // Hide HTML Field Element
40
+ &-tag {
41
+ @include lib.position(absolute, 0 null null 0);
42
+ height: 0px;
43
+ opacity: 0;
44
+ pointer-events: none;
45
+ width: 0px;
46
+ z-index: 0;
47
+ }
48
+ }
@@ -0,0 +1,72 @@
1
+ @use '/lib';
2
+ @use '/tokens';
3
+
4
+ .switch {
5
+ --background: var(--background-default);
6
+ --background-active: var(--background-default);
7
+ --background-default: transparent;
8
+ --background-hover: var(--background-default);
9
+ --background-pressed: var(--background-default);
10
+ --border-color: var(--border-color-default);
11
+ --border-color-default: var(--background);
12
+ --border-radius: 240px;
13
+ --border-style: solid;
14
+ --border-width: 0px;
15
+ --box-shadow: var(--box-shadow-default);
16
+ --box-shadow-default: none;
17
+ --height: var(--size);
18
+ --opacity: var(--opacity-default);
19
+ --opacity-active: var(--opacity-default);
20
+ --opacity-default: 1;
21
+ --opacity-hover: var(--opacity-default);
22
+ --opacity-pressed: var(--opacity-default);
23
+ --padding-horizontal: var(--border-width-400);
24
+ --padding-vertical: var(--border-width-400);
25
+ --rotate: 0deg;
26
+ --scale: var(--scale-default);
27
+ --scale-active: var(--scale-default);
28
+ --scale-default: 1;
29
+ --scale-hover: var(--scale-default);
30
+ --scale-pressed: var(--scale-default);
31
+ --size: var(--size-600);
32
+ --width: var(--width-switch);
33
+ --width-switch: 40px;
34
+
35
+ &::before {
36
+ --box-shadow: 0 1px 0 rgba(0, 0, 0, 0.16);
37
+ --height: calc(var(--size) - (var(--border-width) * 2) - (var(--padding-vertical) * 2));
38
+ --translateX: 0px;
39
+ --translateY: 0px;
40
+ --width: var(--height);
41
+
42
+ #{tokens.state(active, '.field')} & {
43
+ --translateX: calc(var(--width-switch) - (var(--border-width) * 2) - var(--height) - (var(--padding-horizontal) * 2));
44
+ }
45
+ }
46
+
47
+ #{tokens.state(inactive, 'label')},
48
+ #{tokens.state(inactive)} {
49
+ @include tokens.state(hover) {
50
+ --background: var(--background-hover);
51
+ --border-color: var(--border-color-hover);
52
+ --box-shadow: var(--box-shadow-hover);
53
+ --color: var(--color-hover);
54
+ --opacity: var(--opacity-hover);
55
+ --scale: var(--scale-hover);
56
+ }
57
+
58
+ @include tokens.state(pressed) {
59
+ --background: var(--background-pressed);
60
+ --border-color: var(--border-color-pressed);
61
+ --box-shadow: var(--box-shadow-pressed);
62
+ --color: var(--color-pressed);
63
+ --opacity: var(--opacity-pressed);
64
+ --scale: var(--scale-pressed);
65
+ }
66
+ }
67
+
68
+ #{tokens.state(active)} {
69
+ --opacity: var(--opacity-active);
70
+ --scale: var(--scale-active);
71
+ }
72
+ }
@@ -8,4 +8,35 @@
8
8
  position: relative;
9
9
  transition: color var(--transition-duration) ease-in-out;
10
10
  width: var(--width);
11
+
12
+
13
+ &--error {
14
+ animation: textError 0.32s 1 linear;
15
+
16
+ @keyframes textError {
17
+ 0% {
18
+ transform: translate(8px);
19
+ }
20
+
21
+ 20% {
22
+ transform: translate(-8px);
23
+ }
24
+
25
+ 40% {
26
+ transform: translate(4px);
27
+ }
28
+
29
+ 60% {
30
+ transform: translate(-4px);
31
+ }
32
+
33
+ 80% {
34
+ transform: translate(2px);
35
+ }
36
+
37
+ 100% {
38
+ transform: translate(0px);
39
+ }
40
+ }
41
+ }
11
42
  }
@@ -0,0 +1,51 @@
1
+ import { reactive } from '@esportsplus/reactivity';
2
+ import { html, type Attributes } from '@esportsplus/template';
3
+ import { omit } from '@esportsplus/utilities';
4
+ import form from '~/components/form';
5
+ import template from '~/components/template';
6
+ import './scss/index.scss';
7
+
8
+
9
+ type A = Attributes & {
10
+ 'textarea-tag'?: Attributes;
11
+ state?: { active: boolean, error: string };
12
+ };
13
+
14
+
15
+ const OMIT = ['textarea-tag'];
16
+
17
+
18
+ export default template.factory(
19
+ function(attributes: A, content) {
20
+ let a = attributes['textarea-tag'],
21
+ state = attributes.state || reactive({
22
+ active: false,
23
+ error: ''
24
+ });
25
+
26
+ return html`
27
+ <label
28
+ class='textarea'
29
+ ${{
30
+ class: () => state.active && '--active',
31
+ onfocusin: () => {
32
+ state.active = true;
33
+ },
34
+ onfocusout: () => {
35
+ state.active = false;
36
+ }
37
+ }}
38
+ ${a ? omit(attributes, OMIT) : attributes}
39
+ >
40
+ <textarea
41
+ class='textarea-tag'
42
+ onrender=${form.input.onrender(state)}
43
+ ${a}
44
+ >
45
+ ${a?.value as string}
46
+ </textarea>
47
+ ${content}
48
+ </label>
49
+ `;
50
+ }
51
+ );
@@ -0,0 +1,26 @@
1
+ .textarea {
2
+ align-items: center;
3
+ background: var(--background);
4
+ border: var(--border-width) var(--border-style) var(--border-color);
5
+ border-radius: var(--border-radius);
6
+ cursor: text;
7
+ display: flex;
8
+ flex-wrap: wrap;
9
+ font-size: var(--font-size);
10
+ line-height: var(--line-height);
11
+ position: relative;
12
+ width: 100%;
13
+
14
+ &:invalid,
15
+ &:required {
16
+ box-shadow: none;
17
+ }
18
+
19
+ &-tag {
20
+ color: var(--color);
21
+ flex: 1 1 auto;
22
+ padding: var(--padding-vertical) var(--padding-horizontal);
23
+ min-width: 0;
24
+ white-space: normal;
25
+ }
26
+ }
@@ -0,0 +1,49 @@
1
+ @use '/tokens';
2
+
3
+ .textarea {
4
+ --background: var(--background-default);
5
+ --background-active: var(--background-default);
6
+ --background-default: transparent;
7
+ --background-hover: var(--background-default);
8
+ --background-pressed: var(--background-default);
9
+ --border-color: var(--border-color-default);
10
+ --border-color-default: var(--background);
11
+ --border-radius: var(--border-radius-400);
12
+ --border-style: solid;
13
+ --border-width: 0px;
14
+ --box-shadow: var(--box-shadow-default);
15
+ --box-shadow-default: none;
16
+ --color: var(--color-default);
17
+ --color-active: var(--color-default);
18
+ --color-default: var(--color-text-400);
19
+ --color-hover: var(--color-default);
20
+ --color-pressed: var(--color-default);
21
+ --font-size: var(--font-size-400);
22
+ --line-height: var(--line-height-400);
23
+ --padding-horizontal: var(--size-400);
24
+ --padding-vertical: var(--size-400);
25
+ --size: var(--size-400);
26
+
27
+ #{tokens.state(inactive)} {
28
+ @include tokens.state(hover) {
29
+ --background: var(--background-hover);
30
+ --border-color: var(--border-color-hover);
31
+ --box-shadow: var(--box-shadow-hover);
32
+ --color: var(--color-hover);
33
+ }
34
+
35
+ @include tokens.state(pressed) {
36
+ --background: var(--background-pressed);
37
+ --border-color: var(--border-color-pressed);
38
+ --box-shadow: var(--box-shadow-pressed);
39
+ --color: var(--color-pressed);
40
+ }
41
+ }
42
+
43
+ #{tokens.state(active)} {
44
+ --background: var(--background-active);
45
+ --border-color: var(--border-color-active);
46
+ --box-shadow: var(--box-shadow-active);
47
+ --color: var(--color-active);
48
+ }
49
+ }
@@ -1 +1,36 @@
1
- @use 'modern-normalize/modern-normalize.css';
1
+ @use 'modern-normalize/modern-normalize.css';
2
+
3
+ button,
4
+ input,
5
+ select,
6
+ textarea {
7
+ background: transparent;
8
+ border-radius: 0;
9
+ border: 0;
10
+ font-family: inherit;
11
+ font-size: inherit;
12
+ line-height: inherit;
13
+ margin: 0;
14
+ padding: 0;
15
+
16
+ &,
17
+ &:active,
18
+ &:focus,
19
+ &:hover {
20
+ outline: none;
21
+ }
22
+
23
+ &:invalid {
24
+ box-shadow: none;
25
+ }
26
+ }
27
+
28
+ form {
29
+ margin: 0;
30
+ padding: 0;
31
+ width: 100%;
32
+ }
33
+
34
+ label {
35
+ cursor: pointer;
36
+ }