@crowdstrike/glide-core 0.5.1 → 0.6.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.
Files changed (242) hide show
  1. package/README.md +11 -1
  2. package/dist/accordion.js +1 -1
  3. package/dist/accordion.styles.js +5 -4
  4. package/dist/accordion.test.basics.js +109 -0
  5. package/dist/accordion.test.events.js +39 -0
  6. package/dist/button-group.button.js +1 -1
  7. package/dist/button-group.button.styles.js +6 -5
  8. package/dist/button-group.button.test.basics.js +169 -0
  9. package/dist/button-group.button.test.events.js +73 -0
  10. package/dist/button-group.js +1 -1
  11. package/dist/button-group.styles.js +3 -3
  12. package/dist/button-group.test.basics.js +268 -0
  13. package/dist/button-group.test.events.js +291 -0
  14. package/dist/button.d.ts +3 -2
  15. package/dist/button.js +1 -1
  16. package/dist/button.styles.js +5 -5
  17. package/dist/button.test.basics.js +202 -0
  18. package/dist/button.test.events.js +25 -0
  19. package/dist/button.test.form.js +49 -0
  20. package/dist/checkbox-group.js +1 -1
  21. package/dist/checkbox-group.styles.js +2 -2
  22. package/dist/checkbox-group.test.basics.js +119 -0
  23. package/dist/checkbox-group.test.events.js +110 -0
  24. package/dist/checkbox-group.test.focus.js +45 -0
  25. package/dist/checkbox-group.test.form.js +130 -0
  26. package/dist/checkbox-group.test.validity.js +75 -0
  27. package/dist/checkbox.js +1 -1
  28. package/dist/checkbox.styles.js +7 -4
  29. package/dist/checkbox.test.basics.js +89 -0
  30. package/dist/checkbox.test.events.js +87 -0
  31. package/dist/checkbox.test.focus.js +38 -0
  32. package/dist/checkbox.test.form.js +115 -0
  33. package/dist/checkbox.test.states.js +62 -0
  34. package/dist/checkbox.test.validity.js +51 -0
  35. package/dist/drawer.d.ts +2 -2
  36. package/dist/drawer.js +1 -15
  37. package/dist/drawer.styles.js +14 -4
  38. package/dist/drawer.test.accessibility.js +22 -0
  39. package/dist/drawer.test.basics.js +43 -0
  40. package/dist/drawer.test.closing.js +37 -0
  41. package/dist/drawer.test.events.js +52 -0
  42. package/dist/drawer.test.floating-components.d.ts +1 -0
  43. package/dist/drawer.test.floating-components.js +51 -0
  44. package/dist/drawer.test.methods.js +34 -0
  45. package/dist/dropdown.d.ts +4 -2
  46. package/dist/dropdown.js +1 -1
  47. package/dist/dropdown.option.d.ts +0 -2
  48. package/dist/dropdown.option.js +1 -1
  49. package/dist/dropdown.option.styles.js +2 -2
  50. package/dist/dropdown.option.test.basics.js +59 -0
  51. package/dist/dropdown.option.test.basics.multiple.js +26 -0
  52. package/dist/dropdown.option.test.basics.single.js +20 -0
  53. package/dist/dropdown.option.test.events.js +27 -0
  54. package/dist/dropdown.option.test.focus.js +11 -0
  55. package/dist/dropdown.option.test.interactions.multiple.js +82 -0
  56. package/dist/dropdown.option.test.interactions.single.js +22 -0
  57. package/dist/dropdown.styles.js +26 -6
  58. package/dist/dropdown.test.basics.filterable.js +84 -0
  59. package/dist/dropdown.test.basics.js +233 -0
  60. package/dist/dropdown.test.basics.multiple.js +270 -0
  61. package/dist/dropdown.test.basics.single.js +79 -0
  62. package/dist/dropdown.test.events.js +268 -0
  63. package/dist/dropdown.test.events.multiple.js +130 -0
  64. package/dist/dropdown.test.focus.d.ts +1 -0
  65. package/dist/dropdown.test.focus.filterable.js +154 -0
  66. package/dist/dropdown.test.focus.js +28 -0
  67. package/dist/dropdown.test.focus.multiple.js +181 -0
  68. package/dist/dropdown.test.focus.single.js +53 -0
  69. package/dist/dropdown.test.form.js +140 -0
  70. package/dist/dropdown.test.form.multiple.js +149 -0
  71. package/dist/dropdown.test.form.single.js +128 -0
  72. package/dist/dropdown.test.interactions.filterable.js +449 -0
  73. package/dist/dropdown.test.interactions.js +446 -0
  74. package/dist/dropdown.test.interactions.multiple.js +908 -0
  75. package/dist/dropdown.test.interactions.single.js +466 -0
  76. package/dist/dropdown.test.validity.js +46 -0
  77. package/dist/icon-button.d.ts +3 -2
  78. package/dist/icon-button.js +1 -1
  79. package/dist/icon-button.styles.js +12 -12
  80. package/dist/icon-button.test.basics.js +110 -0
  81. package/dist/icons/checked.js +1 -1
  82. package/dist/icons/magnifying-glass.js +1 -1
  83. package/dist/input.js +1 -1
  84. package/dist/input.styles.js +4 -3
  85. package/dist/input.test.basics.js +169 -0
  86. package/dist/input.test.events.js +97 -0
  87. package/dist/input.test.focus.js +54 -0
  88. package/dist/input.test.form.js +56 -0
  89. package/dist/input.test.validity.js +50 -0
  90. package/dist/label.js +1 -1
  91. package/dist/label.styles.js +13 -15
  92. package/dist/label.test.basics.js +129 -0
  93. package/dist/library/expect-argument-error.js +1 -1
  94. package/dist/library/localize.d.ts +17 -0
  95. package/dist/library/localize.js +1 -0
  96. package/dist/library/ow.js +1 -1
  97. package/dist/library/ow.test.js +55 -0
  98. package/dist/library/set-containing-block.d.ts +15 -0
  99. package/dist/library/set-containing-block.js +1 -0
  100. package/dist/menu.button.d.ts +1 -2
  101. package/dist/menu.button.js +1 -1
  102. package/dist/menu.button.styles.js +3 -3
  103. package/dist/menu.button.test.basics.js +42 -0
  104. package/dist/menu.d.ts +7 -2
  105. package/dist/menu.js +1 -1
  106. package/dist/menu.link.d.ts +1 -2
  107. package/dist/menu.link.js +1 -1
  108. package/dist/menu.link.styles.js +3 -3
  109. package/dist/menu.link.test.basics.js +46 -0
  110. package/dist/menu.options.d.ts +22 -0
  111. package/dist/menu.options.js +1 -0
  112. package/dist/menu.options.styles.d.ts +2 -0
  113. package/dist/menu.options.styles.js +33 -0
  114. package/dist/menu.options.test.basics.d.ts +2 -0
  115. package/dist/menu.options.test.basics.js +43 -0
  116. package/dist/menu.stories.d.ts +1 -0
  117. package/dist/menu.styles.js +7 -31
  118. package/dist/menu.test.basics.d.ts +1 -0
  119. package/dist/menu.test.basics.js +183 -0
  120. package/dist/menu.test.focus.d.ts +0 -1
  121. package/dist/menu.test.focus.js +84 -0
  122. package/dist/menu.test.interactions.d.ts +1 -1
  123. package/dist/menu.test.interactions.js +664 -0
  124. package/dist/modal.icon-button.js +1 -1
  125. package/dist/modal.icon-button.styles.js +2 -2
  126. package/dist/modal.icon-button.test.basics.js +45 -0
  127. package/dist/modal.js +1 -15
  128. package/dist/modal.styles.js +4 -7
  129. package/dist/modal.tertiary-icon.d.ts +1 -0
  130. package/dist/modal.tertiary-icon.js +1 -1
  131. package/dist/modal.tertiary-icon.test.basics.js +59 -0
  132. package/dist/modal.test.accessibility.js +48 -0
  133. package/dist/modal.test.basics.js +203 -0
  134. package/dist/modal.test.close.js +38 -0
  135. package/dist/modal.test.events.js +110 -0
  136. package/dist/modal.test.floating-components.d.ts +1 -0
  137. package/dist/modal.test.floating-components.js +62 -0
  138. package/dist/modal.test.lock-scroll.js +76 -0
  139. package/dist/modal.test.methods.js +23 -0
  140. package/dist/modal.test.scrollbars.js +19 -0
  141. package/dist/radio-group.js +1 -1
  142. package/dist/radio-group.styles.js +20 -24
  143. package/dist/radio-group.test.basics.js +323 -0
  144. package/dist/radio-group.test.events.js +277 -0
  145. package/dist/radio-group.test.focus.js +75 -0
  146. package/dist/radio-group.test.form.js +104 -0
  147. package/dist/radio-group.test.validity.js +228 -0
  148. package/dist/radio.js +1 -1
  149. package/dist/radio.styles.js +14 -31
  150. package/dist/split-button.d.ts +27 -0
  151. package/dist/split-button.js +1 -0
  152. package/dist/split-button.stories.d.ts +17 -0
  153. package/dist/split-button.styles.d.ts +2 -0
  154. package/dist/split-button.styles.js +102 -0
  155. package/dist/split-button.test.basics.d.ts +1 -0
  156. package/dist/split-button.test.basics.js +99 -0
  157. package/dist/split-container.d.ts +31 -0
  158. package/dist/split-container.js +1 -0
  159. package/dist/split-container.styles.d.ts +2 -0
  160. package/dist/split-container.styles.js +134 -0
  161. package/dist/split-container.test.basics.d.ts +3 -0
  162. package/dist/split-container.test.basics.js +440 -0
  163. package/dist/split-container.test.interactions.d.ts +1 -0
  164. package/dist/split-container.test.interactions.js +20 -0
  165. package/dist/split-link.d.ts +25 -0
  166. package/dist/split-link.js +1 -0
  167. package/dist/split-link.test.basics.d.ts +1 -0
  168. package/dist/split-link.test.basics.js +92 -0
  169. package/dist/split-link.test.interactions.d.ts +1 -0
  170. package/dist/split-link.test.interactions.js +19 -0
  171. package/dist/status-indicator.js +1 -1
  172. package/dist/status-indicator.styles.js +2 -2
  173. package/dist/status-indicator.test.basics.js +102 -0
  174. package/dist/styles/focus-outline.js +1 -4
  175. package/dist/styles/variables.css +1 -1
  176. package/dist/styles/visually-hidden.js +1 -11
  177. package/dist/tab.group.js +1 -1
  178. package/dist/tab.group.styles.js +2 -2
  179. package/dist/tab.group.test.basics.js +185 -0
  180. package/dist/tab.js +1 -1
  181. package/dist/tab.panel.js +1 -1
  182. package/dist/tab.panel.styles.js +3 -3
  183. package/dist/tab.styles.js +80 -55
  184. package/dist/tab.test.basics.js +71 -0
  185. package/dist/tag.js +1 -1
  186. package/dist/tag.styles.js +4 -3
  187. package/dist/tag.test.basics.js +118 -0
  188. package/dist/tag.test.events.js +16 -0
  189. package/dist/tag.test.focus.js +11 -0
  190. package/dist/tag.test.translations.d.ts +1 -0
  191. package/dist/tag.test.translations.js +25 -0
  192. package/dist/textarea.js +2 -2
  193. package/dist/textarea.styles.js +5 -4
  194. package/dist/textarea.test.basics.js +140 -0
  195. package/dist/textarea.test.events.js +204 -0
  196. package/dist/textarea.test.form.js +70 -0
  197. package/dist/textarea.test.validity.js +83 -0
  198. package/dist/toasts.js +1 -1
  199. package/dist/toasts.styles.js +2 -2
  200. package/dist/toasts.test.basics.js +94 -0
  201. package/dist/toasts.toast.js +1 -1
  202. package/dist/toasts.toast.styles.js +5 -2
  203. package/dist/toasts.toast.test.basics.js +139 -0
  204. package/dist/toggle.js +1 -1
  205. package/dist/toggle.styles.js +3 -3
  206. package/dist/toggle.test.basics.js +68 -0
  207. package/dist/toggle.test.events.js +29 -0
  208. package/dist/toggle.test.focus.js +9 -0
  209. package/dist/toggle.test.states.js +43 -0
  210. package/dist/tooltip.d.ts +2 -0
  211. package/dist/tooltip.js +1 -1
  212. package/dist/tooltip.styles.js +5 -3
  213. package/dist/tooltip.test.basics.js +64 -0
  214. package/dist/tooltip.test.interactions.js +78 -0
  215. package/dist/translations/en.d.ts +3 -0
  216. package/dist/translations/en.js +1 -0
  217. package/dist/translations/fr.d.ts +3 -0
  218. package/dist/translations/fr.js +1 -0
  219. package/dist/translations/ja.d.ts +3 -0
  220. package/dist/translations/ja.js +1 -0
  221. package/dist/tree.d.ts +1 -0
  222. package/dist/tree.item.d.ts +3 -1
  223. package/dist/tree.item.icon-button.js +1 -1
  224. package/dist/tree.item.icon-button.styles.js +2 -2
  225. package/dist/tree.item.icon-button.test.basics.js +13 -0
  226. package/dist/tree.item.js +1 -1
  227. package/dist/tree.item.menu.d.ts +2 -0
  228. package/dist/tree.item.menu.js +1 -1
  229. package/dist/tree.item.menu.styles.js +2 -2
  230. package/dist/tree.item.menu.test.basics.js +33 -0
  231. package/dist/tree.item.styles.js +23 -8
  232. package/dist/tree.item.test.basics.js +102 -0
  233. package/dist/tree.js +1 -1
  234. package/dist/tree.stories.d.ts +1 -0
  235. package/dist/tree.styles.js +2 -2
  236. package/dist/tree.test.aria.js +86 -0
  237. package/dist/tree.test.basics.js +123 -0
  238. package/dist/tree.test.events.js +19 -0
  239. package/dist/tree.test.focus.js +261 -0
  240. package/package.json +25 -18
  241. /package/dist/{dropdown.option.test.focus.multiple.d.ts → dropdown.option.test.focus.d.ts} +0 -0
  242. /package/dist/{dropdown.option.test.focus.single.d.ts → dropdown.test.events.multiple.d.ts} +0 -0
@@ -0,0 +1,110 @@
1
+ import './icon-button.js';
2
+ import { ArgumentError } from 'ow';
3
+ import { assert, expect, fixture, html } from '@open-wc/testing';
4
+ import GlideCoreIconButton from './icon-button.js';
5
+ import sinon from 'sinon';
6
+ GlideCoreIconButton.shadowRootOptions.mode = 'open';
7
+ const icon = html `<svg
8
+ width="16"
9
+ height="16"
10
+ stroke="currentColor"
11
+ fill="none"
12
+ stroke-linecap="round"
13
+ stroke-linejoin="round"
14
+ stroke-width="2"
15
+ viewBox="0 0 24 24"
16
+ aria-hidden="true"
17
+ >
18
+ <path d="M16.51 9.873l-4.459 4.31-4.458-4.31"></path>
19
+ </svg>`;
20
+ it('registers', async () => {
21
+ expect(window.customElements.get('glide-core-icon-button')).to.equal(GlideCoreIconButton);
22
+ });
23
+ it('is accessible', async () => {
24
+ const component = await fixture(html `<glide-core-icon-button label="test-icon-button"
25
+ >${icon}</glide-core-icon-button
26
+ >`);
27
+ await expect(component).to.be.accessible();
28
+ });
29
+ it('has defaults', async () => {
30
+ const component = await fixture(html `<glide-core-icon-button label="test-icon-button"
31
+ >${icon}</glide-core-icon-button
32
+ >`);
33
+ const button = component.shadowRoot?.querySelector('button');
34
+ assert(button);
35
+ expect(component.ariaControls).to.equal(null);
36
+ expect(component.ariaExpanded).to.equal(null);
37
+ expect(component.ariaHasPopup).to.equal(null);
38
+ expect(component.disabled).to.equal(false);
39
+ expect(component.variant).to.equal('primary');
40
+ expect(button.getAttribute('aria-controls')).to.equal(null);
41
+ expect(button.ariaExpanded).to.equal(null);
42
+ expect(button.ariaHasPopup).to.equal(null);
43
+ expect(button.disabled).to.equal(false);
44
+ expect([...button.classList]).to.deep.equal(['component', 'primary']);
45
+ });
46
+ it('delegates focus', async () => {
47
+ const component = await fixture(html `<glide-core-icon-button label="test-icon-button"
48
+ >${icon}</glide-core-icon-button
49
+ >`);
50
+ component.focus();
51
+ expect(component.shadowRoot?.activeElement).to.equal(component.shadowRoot?.querySelector('button'));
52
+ });
53
+ it('uses the provided "label" for the aria-label', async () => {
54
+ const component = await fixture(html `<glide-core-icon-button label="test-icon-button"
55
+ >${icon}</glide-core-icon-button
56
+ >`);
57
+ expect(component.shadowRoot?.querySelector('button')?.getAttribute('aria-label')).to.equal('test-icon-button');
58
+ });
59
+ it('renders a default slot', async () => {
60
+ const component = await fixture(html `<glide-core-icon-button label="test-icon-button"
61
+ ><span data-content>Inner content</span></glide-core-icon-button
62
+ >`);
63
+ expect(component.querySelector('[data-content]')).to.be.ok;
64
+ expect(component.querySelector('[data-content]')).to.be.visible;
65
+ });
66
+ it('renders a primary variant', async () => {
67
+ const component = await fixture(html `<glide-core-icon-button label="test-icon-button" variant="primary"
68
+ >${icon}</glide-core-icon-button
69
+ >`);
70
+ expect([
71
+ ...component.shadowRoot.querySelector('button').classList,
72
+ ]).to.deep.equal(['component', 'primary']);
73
+ });
74
+ it('renders a secondary variant', async () => {
75
+ const component = await fixture(html `<glide-core-icon-button label="test-icon-button" variant="secondary"
76
+ >${icon}</glide-core-icon-button
77
+ >`);
78
+ expect([
79
+ ...component.shadowRoot.querySelector('button').classList,
80
+ ]).to.deep.equal(['component', 'secondary']);
81
+ });
82
+ it('renders a tertiary variant', async () => {
83
+ const component = await fixture(html `<glide-core-icon-button label="test-icon-button" variant="tertiary"
84
+ >${icon}</glide-core-icon-button
85
+ >`);
86
+ expect([
87
+ ...component.shadowRoot.querySelector('button').classList,
88
+ ]).to.deep.equal(['component', 'tertiary']);
89
+ });
90
+ it('sets the disabled attribute', async () => {
91
+ const component = await fixture(html `<glide-core-icon-button label="test-icon-button" disabled
92
+ >${icon}</glide-core-icon-button
93
+ >`);
94
+ expect(component.disabled).to.equal(true);
95
+ expect(component.shadowRoot?.querySelector('button')?.disabled).to.equal(true);
96
+ });
97
+ it('throws if it does not have a default slot', async () => {
98
+ const spy = sinon.spy();
99
+ try {
100
+ await fixture(html `<glide-core-icon-button
101
+ label="test-icon-button"
102
+ ></glide-core-icon-button>`);
103
+ }
104
+ catch (error) {
105
+ if (error instanceof ArgumentError) {
106
+ spy();
107
+ }
108
+ }
109
+ expect(spy.called).to.be.true;
110
+ });
@@ -1 +1 @@
1
- "use strict";import{svg as e}from"lit/static-html.js";export default e`<svg fill="none" viewBox="0 0 24 24" style="height: var(--size, 0.875rem); width: var(--size, 0.875rem);"><path d="M20 6L9 17L4 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
1
+ import{svg}from"lit/static-html.js";export default svg`<svg fill="none" viewBox="0 0 24 24" style="height: var(--size, 0.875rem); width: var(--size, 0.875rem);"><path d="M20 6L9 17L4 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
@@ -1 +1 @@
1
- "use strict";import{svg as o}from"lit/static-html.js";export default o`<svg class="search-icon" fill="none" width="16" height="16" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"/></svg>`;
1
+ import{svg}from"lit/static-html.js";export default svg`<svg class="search-icon" fill="none" width="16" height="16" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"/></svg>`;
package/dist/input.js CHANGED
@@ -1 +1 @@
1
- "use strict";var Y=Object.defineProperty;var Z=Object.getOwnPropertyDescriptor;var i=(r,a,t,u)=>{for(var p=u>1?void 0:u?Z(a,t):a,S=r.length-1,B;S>=0;S--)(B=r[S])&&(p=(u?B(a,t,p):B(p))||p);return u&&p&&Y(a,t,p),p};var R=(r,a,t)=>{if(!a.has(r))throw TypeError("Cannot "+t)};var s=(r,a,t)=>(R(r,a,"read from private field"),t?t.call(r):a.get(r)),l=(r,a,t)=>{if(a.has(r))throw TypeError("Cannot add the same private member more than once");a instanceof WeakSet?a.add(r):a.set(r,t)},P=(r,a,t,u)=>(R(r,a,"write to private field"),u?u.call(r,t):a.set(r,t),t);var n=(r,a,t)=>(R(r,a,"access private method"),t);var g,h,y,b,$,w,F,d,c,x,H,E,j,V,z,L,D,T,C,M,U,v,f;import"./icon-button.js";import"./label.js";import{LitElement as q,html as m,nothing as _}from"lit";import{classMap as N}from"lit/directives/class-map.js";import{createRef as J,ref as K}from"lit/directives/ref.js";import{customElement as Q,property as o,queryAssignedNodes as O,state as k}from"lit/decorators.js";import{ifDefined as A}from"lit/directives/if-defined.js";import W from"./icons/magnifying-glass.js";import X from"./input.styles.js";export const SUPPORTED_TYPES=["email","number","password","search","tel","text","url"];let e=class extends q{constructor(){super();l(this,b);l(this,w);l(this,d);l(this,x);l(this,E);l(this,V);l(this,L);l(this,T);l(this,M);l(this,v);this.type="text";this.value="";this.hideLabel=!1;this.orientation="horizontal";this.clearable=!1;this.spellcheck=!1;this.autocapitalize="on";this.passwordToggle=!1;this.required=!1;this.readonly=!1;this.disabled=!1;this.hasFocus=!1;this.isReportValidityOrSubmit=!1;this.passwordVisible=!1;l(this,g,J());l(this,h,void 0);l(this,y,({formData:t})=>{this.name&&this.value&&!this.disabled&&t.append(this.name,this.value)});P(this,h,this.attachInternals()),this.addEventListener("invalid",t=>{t?.preventDefault(),this.isCheckingValidity||(this.isReportValidityOrSubmit=!0,this.focus())})}get form(){return s(this,h).form}get validity(){return s(this,h).validity}get willValidate(){return s(this,h).willValidate}blur(){s(this,d,c)?.blur()}checkValidity(){return this.isCheckingValidity=!0,s(this,h).checkValidity()}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",s(this,y))}firstUpdated(){n(this,v,f).call(this)}formAssociatedCallback(){this.form?.addEventListener("formdata",s(this,y))}formResetCallback(){this.value=this.getAttribute("value")??""}get isTypeSearch(){return this.type==="search"}get hasClearIcon(){return this.clearable&&!this.disabled&&!this.readonly}get isClearIconVisible(){return this.hasClearIcon&&this.value.length>0}render(){return m`<glide-core-label orientation="${this.orientation}" ?disabled="${this.disabled}" ?error="${s(this,w,F)||s(this,b,$)}" ?hide="${this.hideLabel}" ?required="${this.required}"><slot name="tooltip" slot="tooltip"></slot><label for="input">${this.label}</label><div class="${N({"input-box":!0,focused:this.hasFocus,empty:this.value==="",disabled:this.disabled,readonly:this.readonly&&!this.disabled,error:s(this,w,F)||s(this,b,$)})}" slot="control"><slot name="prefix"></slot><input aria-describedby="meta" id="input" type="${this.type==="password"&&this.passwordVisible?"text":this.type}" .value="${this.value}" placeholder="${A(this.placeholder)}" autocapitalize="${A(this.autocapitalize)}" spellcheck="${this.spellcheck}" ?required="${this.required}" ?readonly="${this.readonly}" ?disabled="${this.disabled}" @focus="${n(this,L,D)}" @blur="${n(this,x,H)}" @change="${n(this,E,j)}" @input="${n(this,T,C)}" ${K(s(this,g))}> ${this.hasClearIcon?m`<glide-core-icon-button variant="tertiary" class="${N({"clear-icon-button":!0,"clear-icon-button--visible":this.isClearIconVisible})}" aria-label="Clear entry" @click="${n(this,V,z)}" tabindex="-1"><slot name="clear-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 6L18 18" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M18 6L6 18" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></slot></glide-core-icon-button>`:""} ${this.type==="password"&&this.passwordToggle&&!this.disabled?m`<glide-core-icon-button variant="tertiary" class="password-toggle" aria-label="${this.passwordVisible?"Hide password":"Show password"}" aria-controls="input" aria-expanded="${this.passwordVisible?"true":"false"}" @click="${n(this,M,U)}" tabindex="-1">${this.passwordVisible?m`<svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88"/></svg>`:m`<svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z"/><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/></svg>`}</glide-core-icon-button>`:""}<div class="suffix">${this.isTypeSearch?W:m`<slot name="suffix"></slot>`}</div></div><div class="meta" id="meta" slot="description"><slot class="description" name="description"></slot>${this.maxlength?m`<div class="${N({"character-count":!0,error:s(this,b,$)})}">${this.valueCharacterCount}/${this.maxlength}</div>`:_}</div></glide-core-label>`}reportValidity(){return s(this,h).reportValidity()}get valueCharacterCount(){return this.value.length}};g=new WeakMap,h=new WeakMap,y=new WeakMap,b=new WeakSet,$=function(){return!!(this.maxlength&&this.valueCharacterCount>this.maxlength)},w=new WeakSet,F=function(){return!this.disabled&&!this.validity?.valid&&this.isReportValidityOrSubmit},d=new WeakSet,c=function(){return s(this,g).value},x=new WeakSet,H=function(){this.hasFocus=!1},E=new WeakSet,j=function(t){this.value=s(this,d,c).value,n(this,v,f).call(this),this.dispatchEvent(new Event(t.type,t))},V=new WeakSet,z=function(t){this.value="",this.dispatchEvent(new Event("clear",{bubbles:!0})),s(this,d,c)?.focus(),n(this,v,f).call(this),t.stopPropagation()},L=new WeakSet,D=function(){this.hasFocus=!0},T=new WeakSet,C=function(){const t=s(this,d,c).value;this.value=t,n(this,v,f).call(this)},M=new WeakSet,U=function(){this.passwordVisible=!this.passwordVisible},v=new WeakSet,f=async function(){await this.updateComplete,s(this,h).setValidity(s(this,d,c)?.validity,s(this,d,c)?.validationMessage,s(this,d,c))},e.formAssociated=!0,e.shadowRootOptions={...q.shadowRootOptions,mode:"closed",delegatesFocus:!0},e.styles=X,i([o()],e.prototype,"type",2),i([o({reflect:!0})],e.prototype,"name",2),i([o()],e.prototype,"value",2),i([o()],e.prototype,"label",2),i([o({attribute:"hide-label",type:Boolean})],e.prototype,"hideLabel",2),i([o({reflect:!0})],e.prototype,"orientation",2),i([o()],e.prototype,"placeholder",2),i([o({type:Boolean})],e.prototype,"clearable",2),i([o({type:Boolean})],e.prototype,"spellcheck",2),i([o()],e.prototype,"autocapitalize",2),i([o({attribute:"password-toggle",type:Boolean})],e.prototype,"passwordToggle",2),i([o({reflect:!0,type:Boolean})],e.prototype,"required",2),i([o({type:Boolean})],e.prototype,"readonly",2),i([o({type:Boolean})],e.prototype,"disabled",2),i([o({type:Number,converter(t){return t&&Number.parseInt(t,10)}})],e.prototype,"maxlength",2),i([O({slot:"description"})],e.prototype,"descriptionNodes",2),i([O({slot:"prefix"})],e.prototype,"prefixIconNodes",2),i([O({slot:"suffix"})],e.prototype,"suffixIconNodes",2),i([k()],e.prototype,"hasFocus",2),i([k()],e.prototype,"isCheckingValidity",2),i([k()],e.prototype,"isReportValidityOrSubmit",2),i([k()],e.prototype,"passwordVisible",2),e=i([Q("glide-core-input")],e);export{e as default};
1
+ var __decorate=this&&this.__decorate||function(e,t,i,o){var s,r=arguments.length,a=r<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,i):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,i,o);else for(var l=e.length-1;l>=0;l--)(s=e[l])&&(a=(r<3?s(a):r>3?s(t,i,a):s(t,i))||a);return r>3&&a&&Object.defineProperty(t,i,a),a};import"./icon-button.js";import"./label.js";import{LitElement,html,nothing}from"lit";import{LocalizeController}from"./library/localize.js";import{classMap}from"lit/directives/class-map.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property,queryAssignedNodes,state}from"lit/decorators.js";import{ifDefined}from"lit/directives/if-defined.js";import magnifyingGlassIcon from"./icons/magnifying-glass.js";import styles from"./input.styles.js";export const SUPPORTED_TYPES=["email","number","password","search","tel","text","url"];let GlideCoreInput=class GlideCoreInput extends LitElement{static{this.formAssociated=!0}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed",delegatesFocus:!0}}static{this.styles=styles}get form(){return this.#e.form}get validity(){return this.#e.validity}get willValidate(){return this.#e.willValidate}blur(){this.#t?.blur()}checkValidity(){return this.isCheckingValidity=!0,this.#e.checkValidity()}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",this.#i)}firstUpdated(){this.#o()}formAssociatedCallback(){this.form?.addEventListener("formdata",this.#i)}formResetCallback(){this.value=this.getAttribute("value")??""}get isTypeSearch(){return"search"===this.type}get hasClearIcon(){return this.clearable&&!this.disabled&&!this.readonly}get isClearIconVisible(){return this.hasClearIcon&&this.value.length>0}render(){return html`<glide-core-label orientation="${this.orientation}" ?disabled="${this.disabled}" ?error="${this.#s||this.#r}" ?hide="${this.hideLabel}" ?required="${this.required}"><slot name="tooltip" slot="tooltip"></slot><label for="input">${this.label}</label><div class="${classMap({"input-box":!0,focused:this.hasFocus,empty:""===this.value,disabled:this.disabled,readonly:this.readonly&&!this.disabled,error:this.#s||this.#r})}" slot="control"><slot name="prefix"></slot><input aria-describedby="meta" id="input" type="${"password"===this.type&&this.passwordVisible?"text":this.type}" .value="${this.value}" placeholder="${ifDefined(this.placeholder)}" autocapitalize="${ifDefined(this.autocapitalize)}" spellcheck="${this.spellcheck}" ?required="${this.required}" ?readonly="${this.readonly}" ?disabled="${this.disabled}" @focus="${this.#a}" @blur="${this.#l}" @change="${this.#n}" @input="${this.#d}" ${ref(this.#p)}> ${this.hasClearIcon?html`<glide-core-icon-button variant="tertiary" class="${classMap({"clear-icon-button":!0,"clear-icon-button--visible":this.isClearIconVisible})}" aria-label="${this.#h.term("clearEntry")}" @click="${this.#c}" tabindex="-1"><slot name="clear-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 6L18 18" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M18 6L6 18" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></slot></glide-core-icon-button>`:""} ${"password"===this.type&&this.passwordToggle&&!this.disabled?html`<glide-core-icon-button variant="tertiary" class="password-toggle" aria-label="${this.passwordVisible?"Hide password":"Show password"}" aria-controls="input" aria-expanded="${this.passwordVisible?"true":"false"}" @click="${this.#u}" tabindex="-1">${this.passwordVisible?html`<svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88"/></svg>`:html`<svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z"/><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/></svg>`}</glide-core-icon-button>`:""}<div class="suffix">${this.isTypeSearch?magnifyingGlassIcon:html`<slot name="suffix"></slot>`}</div></div><div class="meta" id="meta" slot="description"><slot class="description" name="description"></slot>${this.maxlength?html`<div class="${classMap({"character-count":!0,error:this.#r})}">${this.valueCharacterCount}/${this.maxlength}</div>`:nothing}</div></glide-core-label>`}reportValidity(){return this.#e.reportValidity()}get valueCharacterCount(){return this.value.length}constructor(){super(),this.type="text",this.value="",this.hideLabel=!1,this.orientation="horizontal",this.clearable=!1,this.spellcheck=!1,this.autocapitalize="on",this.passwordToggle=!1,this.required=!1,this.readonly=!1,this.disabled=!1,this.hasFocus=!1,this.isReportValidityOrSubmit=!1,this.passwordVisible=!1,this.#p=createRef(),this.#h=new LocalizeController(this),this.#i=({formData:e})=>{this.name&&this.value&&!this.disabled&&e.append(this.name,this.value)},this.#e=this.attachInternals(),this.addEventListener("invalid",(e=>{e?.preventDefault(),this.isCheckingValidity||(this.isReportValidityOrSubmit=!0,this.focus())}))}#p;#e;#h;#i;get#r(){return Boolean(this.maxlength&&this.valueCharacterCount>this.maxlength)}get#s(){return!this.disabled&&!this.validity?.valid&&this.isReportValidityOrSubmit}get#t(){return this.#p.value}#l(){this.hasFocus=!1}#n(e){this.value=this.#t.value,this.#o(),this.dispatchEvent(new Event(e.type,e))}#c(e){this.value="",this.dispatchEvent(new Event("clear",{bubbles:!0})),this.#t?.focus(),this.#o(),e.stopPropagation()}#a(){this.hasFocus=!0}#d(){const e=this.#t.value;this.value=e,this.#o()}#u(){this.passwordVisible=!this.passwordVisible}async#o(){await this.updateComplete,this.#e.setValidity(this.#t?.validity,this.#t?.validationMessage,this.#t)}};__decorate([property()],GlideCoreInput.prototype,"type",void 0),__decorate([property({reflect:!0})],GlideCoreInput.prototype,"name",void 0),__decorate([property()],GlideCoreInput.prototype,"value",void 0),__decorate([property()],GlideCoreInput.prototype,"label",void 0),__decorate([property({attribute:"hide-label",type:Boolean})],GlideCoreInput.prototype,"hideLabel",void 0),__decorate([property({reflect:!0})],GlideCoreInput.prototype,"orientation",void 0),__decorate([property()],GlideCoreInput.prototype,"placeholder",void 0),__decorate([property({type:Boolean})],GlideCoreInput.prototype,"clearable",void 0),__decorate([property({type:Boolean})],GlideCoreInput.prototype,"spellcheck",void 0),__decorate([property()],GlideCoreInput.prototype,"autocapitalize",void 0),__decorate([property({attribute:"password-toggle",type:Boolean})],GlideCoreInput.prototype,"passwordToggle",void 0),__decorate([property({reflect:!0,type:Boolean})],GlideCoreInput.prototype,"required",void 0),__decorate([property({type:Boolean})],GlideCoreInput.prototype,"readonly",void 0),__decorate([property({type:Boolean})],GlideCoreInput.prototype,"disabled",void 0),__decorate([property({type:Number,converter:e=>e&&Number.parseInt(e,10)})],GlideCoreInput.prototype,"maxlength",void 0),__decorate([queryAssignedNodes({slot:"description"})],GlideCoreInput.prototype,"descriptionNodes",void 0),__decorate([queryAssignedNodes({slot:"prefix"})],GlideCoreInput.prototype,"prefixIconNodes",void 0),__decorate([queryAssignedNodes({slot:"suffix"})],GlideCoreInput.prototype,"suffixIconNodes",void 0),__decorate([state()],GlideCoreInput.prototype,"hasFocus",void 0),__decorate([state()],GlideCoreInput.prototype,"isCheckingValidity",void 0),__decorate([state()],GlideCoreInput.prototype,"isReportValidityOrSubmit",void 0),__decorate([state()],GlideCoreInput.prototype,"passwordVisible",void 0),GlideCoreInput=__decorate([customElement("glide-core-input")],GlideCoreInput);export default GlideCoreInput;
@@ -1,4 +1,4 @@
1
- "use strict";import{css as e}from"lit";export default e`
1
+ import{css}from"lit";export default css`
2
2
  .meta {
3
3
  column-gap: var(--glide-core-spacing-xs);
4
4
  display: flex;
@@ -53,11 +53,12 @@
53
53
  }
54
54
 
55
55
  &.disabled {
56
- background-color: var(--glide-core-surface-base-gray-light);
56
+ background-color: var(--glide-core-surface-disabled);
57
57
  color: var(--glide-core-text-tertiary-disabled);
58
58
  }
59
59
 
60
60
  input {
61
+ background-color: transparent;
61
62
  border: none;
62
63
  color: inherit;
63
64
  cursor: inherit;
@@ -106,4 +107,4 @@
106
107
  .empty .clear-icon-button {
107
108
  visibility: hidden;
108
109
  }
109
- `;
110
+ `;
@@ -0,0 +1,169 @@
1
+ import { expect, fixture, html } from '@open-wc/testing';
2
+ import { sendKeys } from '@web/test-runner-commands';
3
+ import GlideCoreInput from './input.js';
4
+ GlideCoreInput.shadowRootOptions.mode = 'open';
5
+ it('registers', async () => {
6
+ expect(window.customElements.get('glide-core-input')).to.equal(GlideCoreInput);
7
+ });
8
+ it('accepts and contains "value" attribute', async () => {
9
+ const element = await fixture(html `
10
+ <glide-core-input label="Test" value="lorem"></glide-core-input>
11
+ `);
12
+ expect(element.value).to.equal('lorem');
13
+ });
14
+ it('accepts disable attribute and disables the underlying input', async () => {
15
+ const element = await fixture(html `
16
+ <glide-core-input label="Test" disabled></glide-core-input>
17
+ `);
18
+ const inputElement = element.shadowRoot?.querySelector('input');
19
+ expect(inputElement).to.exist;
20
+ expect(inputElement?.hasAttribute('disabled')).to.be.true;
21
+ });
22
+ it('accepts readonly attribute and applies readonly to the underlying input', async () => {
23
+ const element = await fixture(html `
24
+ <glide-core-input label="Test" readonly></glide-core-input>
25
+ `);
26
+ const inputElement = element.shadowRoot?.querySelector('input');
27
+ expect(inputElement).to.exist;
28
+ expect(inputElement?.hasAttribute('readonly')).to.be.true;
29
+ });
30
+ it('accepts a type attribute', async () => {
31
+ const element = await fixture(html `
32
+ <glide-core-input label="Test" type="number"></glide-core-input>
33
+ `);
34
+ const inputElement = element.shadowRoot?.querySelector('input');
35
+ expect(inputElement).to.exist;
36
+ expect(inputElement?.getAttribute('type')).to.equal('number');
37
+ });
38
+ it('changes to type text when password is revealed', async () => {
39
+ const element = await fixture(html `
40
+ <glide-core-input
41
+ label="Test"
42
+ value="password123"
43
+ type="password"
44
+ password-toggle
45
+ ></glide-core-input>
46
+ `);
47
+ const inputElement = element.shadowRoot?.querySelector('input');
48
+ expect(inputElement).to.exist;
49
+ expect(inputElement?.getAttribute('type')).to.equal('password');
50
+ const passwordToggle = element.shadowRoot?.querySelector('.password-toggle');
51
+ passwordToggle?.click();
52
+ await element.updateComplete;
53
+ expect(inputElement?.getAttribute('type')).to.equal('text');
54
+ });
55
+ it('shows search icon with type search', async () => {
56
+ const element = await fixture(html `
57
+ <glide-core-input label="Test" type="search"></glide-core-input>
58
+ `);
59
+ const inputElement = element.shadowRoot?.querySelector('input');
60
+ expect(inputElement).to.exist;
61
+ expect(inputElement?.getAttribute('type')).to.equal('search');
62
+ const searchIcon = element.shadowRoot?.querySelector('.search-icon');
63
+ expect(searchIcon).to.exist;
64
+ });
65
+ it('when using "focus() on input", the native input is focused', async () => {
66
+ const element = await fixture(html `
67
+ <glide-core-input label="Test"></glide-core-input>
68
+ `);
69
+ const inputElement = element.shadowRoot?.querySelector('input');
70
+ element.focus();
71
+ expect(document.activeElement).to.equal(element);
72
+ expect(element.shadowRoot?.activeElement).to.equal(inputElement);
73
+ });
74
+ it('emits input events when text is changed and reports a value through the event target', async () => {
75
+ const element = await fixture(html `
76
+ <glide-core-input label="Test"></glide-core-input>
77
+ `);
78
+ let inputEventCaught = false;
79
+ let value = '';
80
+ element.addEventListener('input', (event) => {
81
+ inputEventCaught = true;
82
+ if (event.target instanceof GlideCoreInput) {
83
+ value = event.target.value;
84
+ }
85
+ });
86
+ element.focus();
87
+ await sendKeys({ type: 'testing' });
88
+ element.blur();
89
+ expect(inputEventCaught).to.be.true;
90
+ expect(value).to.be.equal('testing');
91
+ });
92
+ it('clearable attribute allows for a button which can clear input', async () => {
93
+ const element = await fixture(html `
94
+ <glide-core-input label="Test" clearable></glide-core-input>
95
+ `);
96
+ const clearButton = element.shadowRoot?.querySelector('.clear-icon-button');
97
+ element.focus();
98
+ await sendKeys({ type: 'testing' });
99
+ expect(element.value).to.be.equal('testing');
100
+ clearButton?.click();
101
+ expect(element.value).to.be.equal('');
102
+ });
103
+ it('label correctly displays when provided as an attribute', async () => {
104
+ const element = await fixture(html `
105
+ <glide-core-input label="Test label"></glide-core-input>
106
+ `);
107
+ const labelElement = element?.shadowRoot?.querySelector('label');
108
+ const labelText = labelElement?.textContent?.trim();
109
+ expect(labelText).to.be.equal('Test label');
110
+ });
111
+ it('displays a max character and current character count if maxlength is provided', async () => {
112
+ const element = await fixture(html `
113
+ <glide-core-input label="Test label" maxlength="5"></glide-core-input>
114
+ `);
115
+ const maxCharacterCountContainer = element.shadowRoot?.querySelector('.character-count');
116
+ expect(maxCharacterCountContainer?.textContent?.trim()).to.be.equal('0/5');
117
+ });
118
+ it('supports a "tooltip" slot', async () => {
119
+ const component = await fixture(html `<glide-core-input label="test">
120
+ <div slot="tooltip">Tooltip</div>
121
+ </glide-core-input>`);
122
+ const assignedElements = component.shadowRoot
123
+ ?.querySelector('slot[name="tooltip"]')
124
+ ?.assignedElements();
125
+ expect(assignedElements?.at(0)?.textContent).to.equal('Tooltip');
126
+ });
127
+ it('supports a "description" slot', async () => {
128
+ const element = await fixture(html `
129
+ <glide-core-input label="Test">
130
+ <div slot="description">Description</div>
131
+ </glide-core-input>
132
+ `);
133
+ const assignedElements = element.shadowRoot
134
+ ?.querySelector('slot[name="description"]')
135
+ ?.assignedElements();
136
+ expect(assignedElements?.at(0)?.textContent).to.equal('Description');
137
+ });
138
+ it('supports a "prefix" icon slot', async () => {
139
+ const element = await fixture(html `
140
+ <glide-core-input label="Test">
141
+ <div slot="prefix">
142
+ <span data-svg></span>
143
+ </div>
144
+ </glide-core-input>
145
+ `);
146
+ const assignedElements = element.shadowRoot
147
+ ?.querySelector('slot[name="prefix"]')
148
+ ?.assignedElements();
149
+ const slottedSvg = assignedElements
150
+ ?.at(0)
151
+ ?.querySelector('[data-svg]');
152
+ expect(slottedSvg).to.exist;
153
+ });
154
+ it('supports a "suffix" icon slot', async () => {
155
+ const element = await fixture(html `
156
+ <glide-core-input label="Test">
157
+ <div slot="suffix">
158
+ <span data-svg></span>
159
+ </div>
160
+ </glide-core-input>
161
+ `);
162
+ const assignedElements = element.shadowRoot
163
+ ?.querySelector('slot[name="suffix"]')
164
+ ?.assignedElements();
165
+ const slottedSvg = assignedElements
166
+ ?.at(0)
167
+ ?.querySelector('[data-svg]');
168
+ expect(slottedSvg).to.exist;
169
+ });
@@ -0,0 +1,97 @@
1
+ import './input.js';
2
+ import * as sinon from 'sinon';
3
+ import { aTimeout, expect, fixture, html, oneEvent } from '@open-wc/testing';
4
+ import { sendKeys } from '@web/test-runner-commands';
5
+ // `await aTimeout(0)` is used throughout. Using `oneEvent` instead and
6
+ // expecting it to throw would work. But it wouldn't throw until its
7
+ // timeout, which would make for a slow test. Its timeout can likely be
8
+ // configured. But waiting a turn of the event loop, after which the event
9
+ // will have been dispatched, gets the job done as well.
10
+ it('dispatches a "change" event when typed in', async () => {
11
+ const input = await fixture(html `<glide-core-input></glide-core-input>`);
12
+ setTimeout(async () => {
13
+ input.focus();
14
+ await sendKeys({ type: 'testing' });
15
+ input.blur();
16
+ });
17
+ const event = await oneEvent(input, 'change');
18
+ expect(event instanceof Event).to.be.true;
19
+ expect(event.bubbles).to.be.true;
20
+ });
21
+ it('dispatches an "input" event when typed in', async () => {
22
+ const input = await fixture(html `<glide-core-input></glide-core-input>`);
23
+ setTimeout(() => {
24
+ input.focus();
25
+ sendKeys({ type: 'testing' });
26
+ });
27
+ const event = await oneEvent(input, 'input');
28
+ expect(event instanceof Event).to.be.true;
29
+ expect(event.bubbles).to.be.true;
30
+ });
31
+ it('dispatches an "invalid" event on submit when required and no value', async () => {
32
+ const form = document.createElement('form');
33
+ const input = await fixture(html `<glide-core-input required></glide-core-input>`, {
34
+ parentNode: form,
35
+ });
36
+ setTimeout(() => form.requestSubmit());
37
+ const event = await oneEvent(input, 'invalid');
38
+ expect(event instanceof Event).to.be.true;
39
+ });
40
+ it('dispatches an "invalid" event after `checkValidity` is called when required and no value', async () => {
41
+ const form = document.createElement('form');
42
+ const input = await fixture(html `<glide-core-input required></glide-core-input>`, {
43
+ parentNode: form,
44
+ });
45
+ setTimeout(() => input.checkValidity());
46
+ const event = await oneEvent(input, 'invalid');
47
+ expect(event instanceof Event).to.be.true;
48
+ });
49
+ it('dispatches an "invalid" event after `reportValidity` is called when required and no value', async () => {
50
+ const form = document.createElement('form');
51
+ const input = await fixture(html `<glide-core-input required></glide-core-input>`, {
52
+ parentNode: form,
53
+ });
54
+ setTimeout(() => input.reportValidity());
55
+ const event = await oneEvent(input, 'invalid');
56
+ expect(event instanceof Event).to.be.true;
57
+ });
58
+ it('does not dispatch an "invalid" event after `checkValidity` is called when not required', async () => {
59
+ const form = document.createElement('form');
60
+ const input = await fixture(html `<glide-core-input></glide-core-input>`, {
61
+ parentNode: form,
62
+ });
63
+ const spy = sinon.spy();
64
+ input.addEventListener('invalid', spy);
65
+ input.checkValidity();
66
+ await aTimeout(0);
67
+ expect(spy.notCalled).to.be.true;
68
+ });
69
+ it('does not dispatch an "invalid" event after `checkValidity` is called when required and no value but disabled', async () => {
70
+ const form = document.createElement('form');
71
+ const input = await fixture(html `<glide-core-input disabled required></glide-core-input>`, { parentNode: form });
72
+ const spy = sinon.spy();
73
+ input.addEventListener('invalid', spy);
74
+ input.checkValidity();
75
+ await aTimeout(0);
76
+ expect(spy.notCalled).to.be.true;
77
+ });
78
+ it('does not dispatch an "invalid" event when `reportValidity` is called when not required,', async () => {
79
+ const form = document.createElement('form');
80
+ const input = await fixture(html `<glide-core-input></glide-core-input>`, {
81
+ parentNode: form,
82
+ });
83
+ const spy = sinon.spy();
84
+ input.addEventListener('invalid', spy);
85
+ input.reportValidity();
86
+ await aTimeout(0);
87
+ expect(spy.notCalled).to.be.true;
88
+ });
89
+ it('does not dispatch an "invalid" event when `reportValidity` is called when required and no value but disabled', async () => {
90
+ const form = document.createElement('form');
91
+ const input = await fixture(html `<glide-core-input disabled required></glide-core-input>`, { parentNode: form });
92
+ const spy = sinon.spy();
93
+ input.addEventListener('invalid', spy);
94
+ input.reportValidity();
95
+ await aTimeout(0);
96
+ expect(spy.notCalled).to.be.true;
97
+ });
@@ -0,0 +1,54 @@
1
+ import './input.js';
2
+ import { expect, fixture, html } from '@open-wc/testing';
3
+ import Input from './input.js';
4
+ Input.shadowRootOptions.mode = 'open';
5
+ it('focuses the input when `focus` is called', async () => {
6
+ const input = await fixture(html `<glide-core-input required></glide-core-input>`);
7
+ input.focus();
8
+ const inputElement = input.shadowRoot?.querySelector('input');
9
+ expect(input.shadowRoot?.activeElement).to.equal(inputElement);
10
+ });
11
+ it('focuses the input after submit when required and no value', async () => {
12
+ const form = document.createElement('form');
13
+ const input = await fixture(html `<glide-core-input required></glide-core-input>`, {
14
+ parentNode: form,
15
+ });
16
+ form.requestSubmit();
17
+ const inputElement = input.shadowRoot?.querySelector('input');
18
+ expect(input.shadowRoot?.activeElement).to.be.equal(inputElement);
19
+ });
20
+ it('blurs the input if `blur` is called', async () => {
21
+ const input = await fixture(html `<glide-core-input required></glide-core-input>`);
22
+ input.focus();
23
+ const inputElement = input.shadowRoot?.querySelector('input');
24
+ expect(input.shadowRoot?.activeElement).to.equal(inputElement);
25
+ input.blur();
26
+ await input.updateComplete;
27
+ expect(input.shadowRoot?.activeElement).to.equal(null);
28
+ });
29
+ it('focuses the input after `reportValidity` is called when required and no value', async () => {
30
+ const form = document.createElement('form');
31
+ const input = await fixture(html `<glide-core-input required></glide-core-input>`, {
32
+ parentNode: form,
33
+ });
34
+ input.reportValidity();
35
+ const inputElement = input.shadowRoot?.querySelector('input');
36
+ expect(input.shadowRoot?.activeElement).to.equal(inputElement);
37
+ });
38
+ it('focuses the input after `requestSubmit` is called when required and no value', async () => {
39
+ const form = document.createElement('form');
40
+ const input = await fixture(html `<glide-core-input required></glide-core-input>`, {
41
+ parentNode: form,
42
+ });
43
+ form.requestSubmit();
44
+ const inputElement = input.shadowRoot?.querySelector('input');
45
+ expect(input.shadowRoot?.activeElement).to.equal(inputElement);
46
+ });
47
+ it('does not focus the input after `checkValidity` is called', async () => {
48
+ const form = document.createElement('form');
49
+ const input = await fixture(html `<glide-core-input required></glide-core-input>`, {
50
+ parentNode: form,
51
+ });
52
+ input.checkValidity();
53
+ expect(input.shadowRoot?.activeElement).to.equal(null);
54
+ });
@@ -0,0 +1,56 @@
1
+ import './input.js';
2
+ import { expect, fixture, html } from '@open-wc/testing';
3
+ it('can be reset to initial value', async () => {
4
+ const form = document.createElement('form');
5
+ const input = await fixture(html `<glide-core-input value="value"></glide-core-input>`, {
6
+ parentNode: form,
7
+ });
8
+ input.value = '';
9
+ form.reset();
10
+ expect(input.value).to.equal('value');
11
+ });
12
+ it('can be reset if there was no initial value', async () => {
13
+ const form = document.createElement('form');
14
+ const input = await fixture(html `<glide-core-input></glide-core-input>`, {
15
+ parentNode: form,
16
+ });
17
+ input.value = 'value';
18
+ form.reset();
19
+ expect(input.value).to.equal('');
20
+ });
21
+ it('has `formData` value when it has a value', async () => {
22
+ const form = document.createElement('form');
23
+ await fixture(html `<glide-core-input name="name" value="value"></glide-core-input>`, {
24
+ parentNode: form,
25
+ });
26
+ const formData = new FormData(form);
27
+ expect(formData.get('name')).to.be.equal('value');
28
+ });
29
+ it('has no `formData` value when no value', async () => {
30
+ const form = document.createElement('form');
31
+ await fixture(html `<glide-core-input name="name"></glide-core-input>`, {
32
+ parentNode: form,
33
+ });
34
+ const formData = new FormData(form);
35
+ expect(formData.get('name')).to.be.null;
36
+ });
37
+ it('has no `formData` value when it has a value but disabled', async () => {
38
+ const form = document.createElement('form');
39
+ await fixture(html `<glide-core-input
40
+ name="name"
41
+ value="value"
42
+ disabled
43
+ ></glide-core-input>`, {
44
+ parentNode: form,
45
+ });
46
+ const formData = new FormData(form);
47
+ expect(formData.get('name')).to.be.null;
48
+ });
49
+ it('has no `formData` value when it has a value but without a `name`', async () => {
50
+ const form = document.createElement('form');
51
+ await fixture(html `<glide-core-input value="value"></glide-core-input>`, {
52
+ parentNode: form,
53
+ });
54
+ const formData = new FormData(form);
55
+ expect(formData.get('name')).to.be.null;
56
+ });
@@ -0,0 +1,50 @@
1
+ import './input.js';
2
+ import { expect, fixture, html } from '@open-wc/testing';
3
+ import { sendKeys } from '@web/test-runner-commands';
4
+ import Input from './input.js';
5
+ Input.shadowRootOptions.mode = 'open';
6
+ it('is valid if empty but not required', async () => {
7
+ const input = await fixture(html `<glide-core-input></glide-core-input>`);
8
+ expect(input.validity?.valid).to.be.true;
9
+ expect(input.validity?.valueMissing).to.be.false;
10
+ expect(input.checkValidity()).to.be.true;
11
+ expect(input.reportValidity()).to.be.true;
12
+ });
13
+ it('is valid after being filled in when empty and required', async () => {
14
+ const input = await fixture(html `<glide-core-input required></glide-core-input>`);
15
+ input.focus();
16
+ await sendKeys({ type: 'value' });
17
+ expect(input.validity?.valid).to.be.true;
18
+ expect(input.validity?.valueMissing).to.be.false;
19
+ expect(input.checkValidity()).to.be.true;
20
+ expect(input.reportValidity()).to.be.true;
21
+ });
22
+ it('is invalid if no value and required', async () => {
23
+ const input = await fixture(html `<glide-core-input required></glide-core-input>`);
24
+ expect(input.validity?.valid).to.be.false;
25
+ expect(input.validity?.valueMissing).to.be.true;
26
+ expect(input.willValidate).to.be.true;
27
+ expect(input.checkValidity()).to.be.false;
28
+ expect(input.reportValidity()).to.be.false;
29
+ });
30
+ it('is invalid after value is cleared when required', async () => {
31
+ const input = await fixture(html `<glide-core-input
32
+ clearable
33
+ value="value"
34
+ required
35
+ ></glide-core-input>`);
36
+ const clearButton = input.shadowRoot?.querySelector('.clear-icon-button');
37
+ clearButton?.click();
38
+ await input.updateComplete;
39
+ expect(input.validity?.valid).to.be.false;
40
+ expect(input.validity?.valueMissing).to.be.true;
41
+ expect(input.checkValidity()).to.be.false;
42
+ expect(input.reportValidity()).to.be.false;
43
+ });
44
+ it('is valid if no value and required but disabled', async () => {
45
+ const input = await fixture(html `<glide-core-input disabled required></glide-core-input>`);
46
+ expect(input.validity?.valid).to.be.true;
47
+ expect(input.validity?.valueMissing).to.be.false;
48
+ expect(input.checkValidity()).to.be.true;
49
+ expect(input.reportValidity()).to.be.true;
50
+ });